eZ Components - Authentication ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. contents:: Table of Contents Introduction ============ The purpose of this document is to provide common methods of securing online applications, and links to sources of information. The list of methods presented here is not exhaustive, but can be used as a checklist for ensuring protection against common attacks. Securing databases ================== Store encrypted passwords ------------------------- Don't store the passwords in plain text because anybody will be able to read them if they gain access to the database. Use the PHP functions `md5`_ () or `sha1`_ () to encrypt the passwords and then store them. When retrieving a password for the authentication, use the same function and compare the encrypted versions of the password. To prevent cases where two users happen to choose the same password, a salt can be added to the password. The salt can be the first few characters from the username, and it should be added in front of the password before calling the encrypting function. Although MySQL has it's own password() function, it is recommended to use PHP's md5() or sha1(), because with password() identical passwords will be stored as identical strings, and the passwords might be sent unencrypted between the web server and the MySQL database (depending on configuration). Securing the session ==================== For more information about the techniques discusses in this section, consult the articles `Session fixation`_ and `Session poisoning`_. Store SID in cookies -------------------- Settings in `php.ini`_ affects how the session identifier (SID) is handled by the application - in a cookie or in the GET/POST request. Storing the session identifier in a cookie is preferred (although not entirely hack-proof). The php.ini settings are: :: ; Whether to use cookies. session.use_cookies = 1 ; This option enables administrators to make their users invulnerable to ; attacks which involve passing session ids in URLs; defaults to 0. session.use_only_cookies = 1 ; Don't append the SID to URLs session.use_trans_id = 0 Additionally, make sure PHP is not compiled with the option --enable-trans-id, as this will rewrite URLs to include the SID. This requires informing users to use a browser that supports and accepts cookies. Secure the SID generation ------------------------- By modifying these settings in the `php.ini`_ file, the SID generation will depend on the first bytes of a file instead of the current date and time (default): :: ; What file to use for SID generation session.entropy_file = ; How many characters to use from the entropy file session.entropy_length = 10 For entropy file, the Unix /dev/urandom can be used, which generates a pseudo-random number. Regenerate the SID on every request ----------------------------------- Done by the Authentication component. Accept only server generated SID -------------------------------- Done by the Authentication component. Time-out old SIDs ----------------- Done by the Authentication component. Move the session directory -------------------------- It is possible that attackers might get access to the /tmp directory where sessions are stored by default. Use the following `php.ini`_ setting to specify another directory for this: :: ; where to store the sessions session.save_path = The specified directory must be writable by the user under which PHP is running. Clean-up the session directory ------------------------------ The session garbage collector is run when a new session starts. It's behaviour is controlled by the `php.ini`_ options (the values specified are the default): :: ; after how many seconds the data is seen as garbage and cleaned-up out session.gc_maxlifetime = 1440 ; with what probability the garbage collector is run on every session ; initialization. Use together with gc_divisor session.gc_probability = 1 ; value to divide the gc_probability to obtain the garbage collector ; probability to run. ; Probability = gc_probability/gc_divisor (default: 1/100 = 1%) session.gc_divisor = 100 Change these options to values more appropiate for your needs. Note that running the session garbage collector more often can have negative side-effects on the application's performance. Accept only HTTP cookies ------------------------ A setting in `php.ini`_ can make cookings accessible only by HTTP and prevent the cookies from being read by scripting languages: :: session.cookie_httponly = on Default is off. It is available only from PHP 5.2.0 and not all browsers support this (most notably Firefox). Can prevent identity theft through XSS (`Cross-site scripting`_ ) attacks. Destroy the session at logout ----------------------------- When user logs out, the session must be destroyed to prevent reusing of the same SID by the attacker. Destroy the session if the referrer is suspicious ------------------------------------------------- If the referrer is not the same as the website address, then an attack might be taking place. Verify the client's IP address ------------------------------ At login, the server records the IP address of the client, and then checks at each sensitive request if the stored address is the same as the current one. This can be problematic due to the use of proxy servers. Also the IP address can be spoofed. Verify the client's user-agent ------------------------------ At login, the server records the user-agent of the client, and then checks at each sensitive request if the stored user-agent is the same as the current one. The user-agent can be spoofed, so this should not be the only method to be relyed upon. Disable registering of globals ------------------------------ The `php.ini`_ setting for this is: :: register_globals = off This can prevent attacks which use `Session poisoning`_. From PHP 4.2.0 it is off by default, and it is removed in PHP 6.0.0. Just make sure it isn't turned on by accident. Securing the registration and login process =========================================== Request email confirmation -------------------------- When users register in an online application, use an email confirmation process. This will prevent automated registrations from bots. The registration emails should not contain the password that the user used to register, as it can be seen by people or sniffers. Use CAPTCHAs ------------ Another way to prevent automated registrations is to use CAPTCHAs. Choose one implementation that does not make it too hard for humans to read, but still maintaining a secure enough level to prevent bots using OCR technology. Secure the password recovery process ------------------------------------ If using the `md5`_ () or `sha1`_ () functions in PHP to store the passwords (as discussed earlier), there is no way to recover the password from the database. In this case, the server can generate a temporary password with which the user can login to his account administration tool and change the password to something else. The temporary password can be sent to the user by email. The process of password recovery can be secured more by having the user answer a question which he/she specified during the registration process, such as "What was your pet's name?" or "What is your birthday?. This will prevent the case where anyone can get a new password for an account name which they found out. The password recovery should be limited to only a few uses to prevent attacks. Limit the number of login attempts ---------------------------------- Sometimes an attacker might know a partial password and will try repeteadly to login. Specifying a limited number of permitted login attempts can prevent this. Login to the application for that account should be blocked for a specified amount of time. It can also be blocked for a longer time and an email should be sent to the account owner with a link to the or to the account unlocker tool or to the password recovery tool. Time-out "Keep me logged-in" ---------------------------- When using "Remember me" or "Keep me logged-in" during login, the logged-in time must be limited (eg. 24 hours) to ensure attackers can't gain access when using a stolen computer. Securing the server-side ======================== Protect include files --------------------- Do not use the extension .inc for include files, instead use .php, so that the files will not be displayed in the browser if they are accessed directly. Protect server-side code and data --------------------------------- By adding in the `httpd.conf`_ entries for the directories that contain sensitive code or data of the application, attackers are prevented to see their contents. :: Order deny,allow Deny from all Allow from 127.0.0.1 An alternative is to use a `.htaccess`_ file in every directory that must be protected. :: Order deny,allow Deny from all Allow from 127.0.0.1 The server will access the .htaccess files on every request. The httpd.conf file is accessed only on starting the Apache server. This means there is a small performance hit by using .htaccess files, which must be taken into consideration when developing large applications. Protect sensitive files from search engine spiders -------------------------------------------------- You can create a file named `robots.txt`_ in the website's root directory, with the contents: :: User-agent: * Crawl-delay: 120 Disallow: /path/ Write as many "Disallow: /path/" lines as necessary, with "path" being the directories which should not be indexed by the search engine spiders, like templates, compiled templates, server-side code, configuration directories, log directories, tmp directories, premium content directories, etc. The Crawl-delay setting (in seconds) can prevent a spider indexing the website too quickly (which might cause bottlenecks). There are spiders which don't follow the robots.txt (`bad bots`_). Against these spiders you can use a `bot trap`_ or the httpd.conf or .htaccess files to prevent the bad spiders to access the application directories. The robots.txt file is not needed if you used the previous method (httpd.conf or .htaccess files) to protect directories, as it gives away information about the directory structure of the application. Prevent directory traversal --------------------------- More information can be found on the `Directory traversal`_ article on Wikipedia. Prevent cross-site attacks -------------------------- Recommended reading: - `Cross-site request forgery`_ - `Cross-site cooking`_ - `Cross-site scripting`_ - `Cross-zone scripting`_ Secure file uploads ------------------- Use generated names for uploaded files or mail attachments instead of the original names, so that attacks relying on filenames containing paths will be prevented. Use a maximum file size for uploads, using `php.ini`_: :: ; maximum upload size upload_max_filesize = ; maximum size for POST data post_max_size = ; the temporary directory to keep the uploaded files upload_tmp_dir = /tmp The temporary directory must be writable by the user under PHP is running. The php.ini value for memory_limit should be higher than the upload_max_filesize value. Validate and clean input ------------------------ Prevent SQL injection attacks by validating and cleaning data coming from a web request before running SQL queries on them. Don't rely only on client-side validation for data (although client-side validation can be employed to speed up validation and reduce network load). Do not display errors --------------------- Displaying errors might provide attackers with security information about the application, such as file paths, database schema, etc. The `php.ini`_ settings for this are: :: ; do not display errors display_errors = off ; do not display errors occuring during PHP's startup sequence display_startup_errors = off Securing the client-side ======================== Sending passwords from clients ------------------------------ In order to transmit securely a password from the login page to the server code, the PHP functions `md5`_ () or `sha1`_ () can be used. A more secure way is to add a random number (generated by the server) to the password, and then apply md5() or sha1() to this string. That is because rainbow tables of hashes can be used by attackers to find the unhashed strings. This method requires implementing an md5() or sha1() function in JavaScript, or using an already made one. Since PHP 5.1.2 you can use the function `hash`_ () which has support for different hashing methods (MD5, SHA1, SHA256, etc). One added bonus is that the hash() function is faster to execute than the md5() and sha1() functions. Passwords should be enforced to contain numbers and other characters apart from letters, and/or be at least 8 characters in length, to make them more secure against dictionary and rainbow tables attacks. Use POST forms -------------- Use POST requests instead of GET for operations that may involve modifying the data on the server (add, delete, edit). GET requests should be employed only for retrieving data. Protection from reloads ----------------------- After a request from the client (login, delete, add, buy, etc), it is possible that the user reload the page, thus sending the request again. This should be detected and avoided. Use an encrypted connection --------------------------- Use SSL/TLS to prevent sniffers from stumbling upon sensitive information like usernames, passwords, social security numbers or credit card numbers. References ========== Configuration files - `php.ini`_ - `.htaccess`_ - `httpd.conf`_ - `robots.txt`_ .. _php.ini: http://php.net/manual/en/ini.php .. _.htaccess: http://httpd.apache.org/docs/2.0/howto/htaccess.html .. _httpd.conf: http://httpd.apache.org/docs/2.0/mod/core.html .. _robots.txt: http://www.robotstxt.org/wc/robots.html .. _md5: http://php.net/manual/en/function.md5.php .. _sha1: http://php.net/manual/en/function.sha1.php .. _hash: http://php.net/manual/en/function.hash.php .. _Session fixation: http://en.wikipedia.org/wiki/Session_fixation .. _Session poisoning: http://en.wikipedia.org/wiki/Session_poisoning .. _Directory traversal: http://en.wikipedia.org/wiki/Directory_traversal .. _Cross-site Request forgery: http://en.wikipedia.org/wiki/Cross-site_request_forgery .. _Cross-site Cooking: http://en.wikipedia.org/wiki/Cross-site_cooking .. _Cross-site Scripting: http://en.wikipedia.org/wiki/Cross-site_scripting .. _Cross-zone Scripting: http://en.wikipedia.org/wiki/Cross-zone_scripting .. _bad bots: http://www.kloth.net/internet/badbots.php .. _bot trap: http://www.kloth.net/internet/bottrap.php .. Local Variables: mode: rst fill-column: 79 End: vim: et syn=rst tw=79 nocin