Security for developers

As a MediaWiki developer, you have a responsibility write secure code in a style that is easy to review and audit. This article focuses on the issues related to security and on the best practices used by MediaWiki developers to address these security issues. For issues of coding style, please read the MediaWiki coding conventions.

Every MediaWiki developer should carefully read this article, regardless of their level of experience in web application development and with PHP.

Why security matters
Web application security is a critical issue in the wired world. Websites with security vulnerabilities are an important part of the illicit global infrastructure of malware, spam and phishing. Bot herders crawl the web looking for websites with security vulnerabilities, and then use the vulnerabilities to hijack them. The hijacked website will distribute malware (viruses) to visitors, either via browser vulnerabilities or overtly by social engineering. The downloaded malware turns the client's computer into a "zombie", part of a global network of organised crime aimed at stealing bank account details, sending spam, and extorting money from websites with denial-of-service threats.

Demonstrable security
It's not enough to assure yourself that you are perfect and that your code has no security vulnerabilities. Everyone makes mistakes. All core code, and a good deal of extension code, is reviewed by experienced developers to verify its security. This is a good practice and should be encouraged.

So, write code in such a way that it is demonstrably secure, such that a reviewer can easily tell that it's secure. Don't write code that looks suspicious but is, on careful examination, secure. Such code causes unnecessary reviewer anxiety.

Overview of security vulnerabilities and attacks
This document has a strong focus on the following attacks and security risks. Each MediaWiki developer should be familiar with these issues and have at least a passing understanding of them.

Cross-site scripting (XSS) vulnerabilities allow an attacker to inject malicious code into a website. XSS vulnerabilities are caused by a web application not properly escaping data from external sources (such as GET data, POST data, RSS feeds or URLs). The range of attacks that can be made via XSS are very diverse, ranging from harmless pranks to the hijacking of an authenticated user's account.
 * For detailed information on avoiding XSS vulnerabilities in MediaWiki, read the Cross-site scripting article.

Cross-site request forgery (CSRF or XSRF) attacks use authentication credentials cached in a victim's browser (such as a cookie or cached username and password) to authorize a malicious HTTP request. The malicious HTTP request can be sent in many ways. As long as the requests are processed by a web browser that has cached authentication credentials, a CSRF attack can be attempted.
 * For detailed information on avoiding CSRF vulnerabilities in MediaWiki, read the Cross-site request forgery article.

Register globals is a deprecated feature of PHP. The feature causes data passed to a PHP script via cookies or GET and POST requests to be made available as global variables in the script. Register globals is extremely dangerous, often allowing an attacker to overwrite variables in a script simply by adding parameters to requests. Register globals may be enabled on servers where MediaWiki is installed and MediaWiki developers must write their code to defend against register globals-based variable injection.
 * For detailed information on avoiding variable injection when register globals is enabled, read the Register globals article.

SQL injection relies on poorly validated input being used in a database query, possibly allowing an attacker to run arbitrary SQL queries on your server. The attacker may then be able to fetch private data, destroy data or cause other unintended responses. In the worst case, the injected code could allow the attacker to gain full control of the system by exploiting multiple vulnerabilities in the database server, system utilities and operating system.
 * For detailed information on avoiding SQL injection, read the SQL injection article.

Best practices
{| class="wikitable" | ! If you are working with ... ! have you ...



Cookies

 * reduced reviewer anxiety by using $wgRequest instead of ?
 * fetched cookies using ?
 * set cookies using ?
 * set cookies using ?

Extensions




External programs
""
 * executed the program via wfShellExec?
 * quoted all arguments to external programs using wfEscapeShellArg?
 * quoted all arguments to external programs using wfEscapeShellArg?



Forms

 * used $wgUser->editToken to  implement anti-CSRF measures?
 * reduced reviewer anxiety by using or extending MediaWiki's existing form functionality?
 * reduced reviewer anxiety by using or extending MediaWiki's existing form functionality?



GET data
""
 * reduced reviewer anxiety by using $wgRequest instead of ?
 * reduced reviewer anxiety by using $wgRequest instead of ?



Global variables
""
 * written your code to defend against register globals-based variable injection?
 * written your code to defend against register globals-based variable injection?



Output (API, CSS, JavaScript, HTML, XML, etc.)
Any content that MediaWiki generates can be a vector for XSS attacks. ""
 * used the  and   helper classes?
 * used the  and   helper classes?

POST data
""
 * reduced reviewer anxiety by using $wgRequest instead of ?
 * reduced reviewer anxiety by using $wgRequest instead of ?

Query strings

 * See above
 * See above



Regular expressions
Avoid evaluating regular expression matches with things like,  , and the   option on  :


 * it's easier to end up shoving an arbitrary string into text processed by a regex, causing a code injection vulnerability
 * it's harder to read and maintain code that's mixed into strings
 * static analysis tools won't catch warnings and errors in the code
 * APC can't cache it
 * sometimes has garbage-collection issues

Sometimes you really do need them (obviously eval.php needs to run eval ;) but in most cases like this, we'd rather see the function broken out and referred as a callback.

For future code that runs only under PHP 5.3 and later, note that inline lambda functions will make it easier to make your callback inline while retaining the benefits of code that's written in native syntax instead of strings.



Sessions




Reviewer anxiety
""
 * clearly commented unexpected or odd parts of your code?
 * clearly commented unexpected or odd parts of your code?

SQL queries

 * used MediaWiki's database wrappers?
 * used MediaWiki's database wrappers?


 * }