Category Archives: Web Security

SQL Injection

This is not so much about security but rather about efficiency: security comes as a bonus. You certainly realize that queries must be parsed by the server in order to turn them in meaningful instructions for it to execute them. That is the same situation than with regular programmes where source code must be compiled into machine code, but with the compilation work done by the DB server.

The server will have to do that work pretty much each time it receives a SQL query, unless there’s a way to tell it to remember a query which must be executed several times. Preparing a query is really telling that to the server.

The second idea is to allow a query to be parameterized, since often times programmes need to run queries several times with only a few values changing from one iteration to the next. Parameters make this process easily blend with caching query preparations.

As for how this whole process works, as said earlier, this is just compilation. SQL is parsed, transformed into a abstract syntax tree, many transformations are applied on said tree to produce a more optimal version of it, either by eliminating useless clauses, or reformulate them in way which better leverage the structure of the targeted schema. Then the resulting tree is transformed into the stream of instructions that the server will execute each time the EXECUTE command will be issued. Depending on the place where parameters are placed in the SQL query, the compilations steps maybe delayed after initial parsing, as values may dictate how the optimization should be conducted.

The main reason why injections cannot work on prepared query is that injections rely on SQL syntax, however after statements are prepared, ie. at the time when the injection data is really submitted to the server, SQL parsing has already been done, so syntactic issues cannot occur anymore. parameters are taken “as-is”, without any form of syntactic interpretation within the surrounding query: they are solely coerced to the type required by the expression within which their associated bindings are appearing.

For instance, the classical injection method is to cut short the statement, insert some other commands, and then add a final command to ensure that the trailing SQL code does not proclduce a syntax error.

 SELECT * FROM table WHERE x = ? AND k = 1

If in the above query, we replace the question mark by the following: 0; DROP TABLE table, we realize an injection. The meaning of the statement has been diverted from its original intent, and it will now execute unwanted code. However, the trailing AND k = 1 will produce a syntax error, so we have to append another command which will syntactically correct the whole string, for instance ; SELECT 0 FROM table WHERE 1 = 1.

This injection may only work if the placeholder replacement happens before parsing. Otherwise the whole string bound to ? will be just a string without other syntactic significance. It’s coertion to another type (int, enum, etc.), may produce an error though.

The wikipedia page on the topic does a much better job at covering it than this humble answer, with many examples and references, don’t hesitate to consult it for a better understanding.

SQL Injection Prevention Cheat Sheet


Last revision (mm/dd/yy): 11/5/2015


This article is focused on providing clear, simple, actionable guidance for preventing SQL Injection flaws in your applications. SQL Injection attacks are unfortunately very common, and this is due to two factors:

  1. the significant prevalence of SQL Injection vulnerabilities, and
  2. the attractiveness of the target (i.e., the database typically contains all the interesting/critical data for your application).

It’s somewhat shameful that there are so many successful SQL Injection attacks occurring, because it is EXTREMELY simple to avoid SQL Injection vulnerabilities in your code.

SQL Injection flaws are introduced when software developers create dynamic database queries that include user supplied input. To avoid SQL injection flaws is simple. Developers need to either: a) stop writing dynamic queries; and/or b) prevent user supplied input which contains malicious SQL from affecting the logic of the executed query.

This article provides a set of simple techniques for preventing SQL Injection vulnerabilities by avoiding these two problems. These techniques can be used with practically any kind of programming language with any type of database. There are other types of databases, like XML databases, which can have similar problems (e.g., XPath and XQuery injection) and these techniques can be used to protect them as well.

Primary Defenses:

  • Option #1: Use of Prepared Statements (Parameterized Queries)
  • Option #2: Use of Stored Procedures
  • Option #3: Escaping all User Supplied Input

Additional Defenses:

  • Also Enforce: Least Privilege
  • Also Perform: White List Input Validation
Unsafe Example

SQL injection flaws typically look like this:

The following (Java) example is UNSAFE, and would allow an attacker to inject code into the query that would be executed by the database. The unvalidated “customerName” parameter that is simply appended to the query allows an attacker to inject any SQL code they want. Unfortunately, this method for accessing databases is all too common.

 String query = "SELECT account_balance FROM user_data WHERE user_name = "
   + request.getParameter("customerName");
 try {
 	Statement statement = connection.createStatement( … );
 	ResultSet results = statement.executeQuery( query );

Primary Defenses

Defense Option 1: Prepared Statements (with Parameterized Queries)

The use of prepared statements with variable binding (aka parameterized queries) is how all developers should first be taught how to write database queries. They are simple to write, and easier to understand than dynamic queries. Parameterized queries force the developer to first define all the SQL code, and then pass in each parameter to the query later. This coding style allows the database to distinguish between code and data, regardless of what user input is supplied.

Prepared statements ensure that an attacker is not able to change the intent of a query, even if SQL commands are inserted by an attacker. In the safe example below, if an attacker were to enter the userID of tom’ or ‘1’=’1, the parameterized query would not be vulnerable and would instead look for a username which literally matched the entire string tom’ or ‘1’=’1.

Language specific recommendations:

  • Java EE – use PreparedStatement() with bind variables
  • .NET – use parameterized queries like SqlCommand() or OleDbCommand() with bind variables
  • PHP – use PDO with strongly typed parameterized queries (using bindParam())
  • Hibernate – use createQuery() with bind variables (called named parameters in Hibernate)
  • SQLite – use sqlite3_prepare() to create a statement object

In rare circumstances, prepared statements can harm performance. When confronted with this situation, it is best to either a) strongly validate all data or b) escape all user supplied input using an escaping routine specific to your database vendor as described below, rather than using a prepared statement.

Safe Java Prepared Statement Example

The following code example uses a PreparedStatement, Java’s implementation of a parameterized query, to execute the same database query.

 String custname = request.getParameter("customerName"); // This should REALLY be validated too
 // perform input validation to detect attacks
 String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
 PreparedStatement pstmt = connection.prepareStatement( query );
 pstmt.setString( 1, custname); 
 ResultSet results = pstmt.executeQuery( );
Safe C# .NET Prepared Statement Example

With .NET, it’s even more straightforward. The creation and execution of the query doesn’t change. All you have to do is simply pass the parameters to the query using the Parameters.Add() call as shown here.

 String query = 
 	 "SELECT account_balance FROM user_data WHERE user_name = ?";
 try {
 	OleDbCommand command = new OleDbCommand(query, connection);
 	command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
 	OleDbDataReader reader = command.ExecuteReader();
 	// …
 } catch (OleDbException se) {
 	// error handling

We have shown examples in Java and .NET but practically all other languages, including Cold Fusion, and Classic ASP, support parameterized query interfaces. Even SQL abstraction layers, like the Hibernate Query Language (HQL) have the same type of injection problems (which we call HQL Injection). HQL supports parameterized queries as well, so we can avoid this problem:

Hibernate Query Language (HQL) Prepared Statement (Named Parameters) Examples
 First is an unsafe HQL Statement
 Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
 Here is a safe version of the same query using named parameters
 Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
 safeHQLQuery.setParameter("productid", userSuppliedParameter);

For examples of parameterized queries in other languages, including Ruby, PHP, Cold Fusion, and Perl, see the Query Parameterization Cheat Sheet or

Developers tend to like the Prepared Statement approach because all the SQL code stays within the application. This makes your application relatively database independent.

Defense Option 2: Stored Procedures

Stored procedures have the same effect as the use of prepared statements when implemented safely* which is the norm for most stored procedure languages. They require the developer to just build SQL statements with parameters which are automatically parameterized unless the developer does something largely out of the norm. The difference between prepared statements and stored procedures is that the SQL code for a stored procedure is defined and stored in the database itself, and then called from the application. Both of these techniques have the same effectiveness in preventing SQL injection so your organization should choose which approach makes the most sense for you.

*Note: ‘Implemented safely’ means the stored procedure does not include any unsafe dynamic SQL generation. Developers do not usually generate dynamic SQL inside stored procedures. However, it can be done, but should be avoided. If it can’t be avoided, the stored procedure must use input validation or proper escaping as described in this article to make sure that all user supplied input to the stored procedure can’t be used to inject SQL code into the dynamically generated query. Auditors should always look for uses of sp_execute, execute or exec within SQL Server stored procedures. Similar audit guidelines are necessary for similar functions for other vendors.

There are also several cases where stored procedures can increase risk. For example, on MS SQL server, you have 3 main default roles: db_datareader, db_datawriter and db_owner. Before stored procedures came into use, DBA’s would give db_datareader or db_datawriter rights to the webservice’s user, depending on the requirements. However, stored procedures require execute rights, a role that is not available by default. Some setups where the user management has been centralized, but is limited to those 3 roles, cause all web apps to run under db_owner rights so stored procedures can work. Naturally, that means that if a server is breached the attacker has full rights to the database, where previously they might only have had read-access. More on this topic here.

Safe Java Stored Procedure Example

The following code example uses a CallableStatement, Java’s implementation of the stored procedure interface, to execute the same database query. The “sp_getAccountBalance” stored procedure would have to be predefined in the database and implement the same functionality as the query defined above.

 String custname = request.getParameter("customerName"); // This should REALLY be validated
 try {
 	CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
 	cs.setString(1, custname);
 	ResultSet results = cs.executeQuery();		
 	// … result set handling 
 } catch (SQLException se) {			
 	// … logging and error handling
Safe VB .NET Stored Procedure Example

The following code example uses a SqlCommand, .NET’s implementation of the stored procedure interface, to execute the same database query. The “sp_getAccountBalance” stored procedure would have to be predefined in the database and implement the same functionality as the query defined above.

 	Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
 	command.CommandType = CommandType.StoredProcedure
 	command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
 	Dim reader As SqlDataReader = command.ExecuteReader()
 	‘ …
 Catch se As SqlException 
 	‘ error handling
 End Try

Defense Option 3: Escaping All User Supplied Input

This second technique is to escape user input before putting it in a query. However, this methodology is frail compared to using parameterized queries and we cannot guarantee it will prevent all SQL Injection in all situations. This technique should only be used, with caution, to retrofit legacy code in a cost effective way. Applications built from scratch, or applications requiring low risk tolerance should be built or re-written using parameterized queries.

This technique works like this. Each DBMS supports one or more character escaping schemes specific to certain kinds of queries. If you then escape all user supplied input using the proper escaping scheme for the database you are using, the DBMS will not confuse that input with SQL code written by the developer, thus avoiding any possible SQL injection vulnerabilities.

To find the javadoc specifically for the database encoders, click on the ‘Codec’ class on the left hand side. There are lots of Codecs implemented. The two Database specific codecs are OracleCodec, and MySQLCodec.

Just click on their names in the ‘All Known Implementing Classes:’ at the top of the Interface Codec page.

At this time, ESAPI currently has database encoders for:

  • Oracle
  • MySQL (Both ANSI and native modes are supported)

Database encoders for:

  • SQL Server
  • PostgreSQL

Are forthcoming. If your database encoder is missing, please let us know.

Database Specific Escaping Details

If you want to build your own escaping routines, here are the escaping details for each of the databases that we have developed ESAPI Encoders for:

Oracle Escaping

This information is based on the Oracle Escape character information found here:

Escaping Dynamic Queries

To use an ESAPI database codec is pretty simple. An Oracle example looks something like:

 ESAPI.encoder().encodeForSQL( new OracleCodec(), queryparam );

So, if you had an existing Dynamic query being generated in your code that was going to Oracle that looked like this:

 String query = "SELECT user_id FROM user_data WHERE user_name = '" + req.getParameter("userID") 
 + "' and user_password = '" + req.getParameter("pwd") +"'";
 try {
     Statement statement = connection.createStatement( … );
     ResultSet results = statement.executeQuery( query );

You would rewrite the first line to look like this:

Codec ORACLE_CODEC = new OracleCodec();
 String query = "SELECT user_id FROM user_data WHERE user_name = '" + 
   ESAPI.encoder().encodeForSQL( ORACLE_CODEC, req.getParameter("userID")) + "' and user_password = '"
   + ESAPI.encoder().encodeForSQL( ORACLE_CODEC, req.getParameter("pwd")) +"'";

And it would now be safe from SQL injection, regardless of the input supplied.

For maximum code readability, you could also construct your own OracleEncoder.

 Encoder oe = new OracleEncoder();
 String query = "SELECT user_id FROM user_data WHERE user_name = '" 
   + oe.encode( req.getParameter("userID")) + "' and user_password = '" 
   + oe.encode( req.getParameter("pwd")) +"'";

With this type of solution, all your developers would have to do is wrap each user supplied parameter being passed in into an ESAPI.encoder().encodeForOracle( ) call or whatever you named it, and you would be done.

Turn off character replacement

Use SET DEFINE OFF or SET SCAN OFF to ensure that automatic character replacement is turned off. If this character replacement is turned on, the & character will be treated like a SQLPlus variable prefix that could allow an attacker to retrieve private data.

See and for more information

Escaping Wildcard characters in Like Clauses

The LIKE keyword allows for text scanning searches. In Oracle, the underscore ‘_’ character matches only one character, while the ampersand ‘%’ is used to match zero or more occurrences of any characters. These characters must be escaped in LIKE clause criteria. For example:

SELECT name FROM emp 
WHERE id LIKE '%/_%' ESCAPE '/';
SELECT name FROM emp 
WHERE id LIKE '%\%%' ESCAPE '\';
Oracle 10g escaping

An alternative for Oracle 10g and later is to place { and } around the string to escape the entire string. However, you have to be careful that there isn’t a } character already in the string. You must search for these and if there is one, then you must replace it with }}. Otherwise that character will end the escaping early, and may introduce a vulnerability.

MySQL Escaping

MySQL supports two escaping modes:

  1. ANSI_QUOTES SQL mode, and a mode with this off, which we call
  2. MySQL mode.

ANSI SQL mode: Simply encode all ‘ (single tick) characters with ” (two single ticks)

MySQL mode, do the following:

 NUL (0x00) --> \0  [This is a zero, not the letter O]
 BS  (0x08) --> \b
 TAB (0x09) --> \t
 LF  (0x0a) --> \n
 CR  (0x0d) --> \r
 SUB (0x1a) --> \Z
 "   (0x22) --> \"
 %   (0x25) --> \%
 '   (0x27) --> \'
 \   (0x5c) --> \\
 _   (0x5f) --> \_ 
 all other non-alphanumeric characters with ASCII values less than 256  --> \c
 where 'c' is the original non-alphanumeric character.

This information is based on the MySQL Escape character information found here:

SQL Server Escaping

We have not implemented the SQL Server escaping routine yet, but the following has good pointers to articles describing how to prevent SQL injection attacks on SQL server

DB2 Escaping

This information is based on DB2 WebQuery special characters found here: as well as some information from Oracle’s JDBC DB2 driver found here:

Information in regards to differences between several DB2 Universal drivers can be found here:

Hex-encoding all input

A somewhat special case of escaping is the process of hex-encode the entire string received from the user (this can be seen as escaping every character). The web application should hex-encode the user input before including it to the SQL statement. The SQL statement should take into account this fact, and accordingly compare the data. For example, if we have to look up a record matching a sessionID, and the user transmitted the string abc123 as session ID, the select statement would be:

   SELECT ... FROM session
   WHERE hex_encode (sessionID) = '606162313233'

(hex_encode should be replace by the particular facility for the database being used). The string 606162313233 is the hex encoded version of the string received from the user (it is the sequence of hex values of the ASCII/UTF-8 codes of the user data).

If an attacker were to transmit a string containing a single-quote character followed by their attempt to inject SQL code, the constructed SQL statement will only look like:

   WHERE hex_encode ( ... ) = '2720 ... '

27 being the ASCII code (in hex) of the single-quote, which is simply hex-encoded like any other character in the string. The resulting SQL can only contain numeric digits and a to f letters, and never any special character that could enable an SQL injection.

Additional Defenses

Beyond adopting one of the three primary defenses, we also recommend adopting all of these additional defenses in order to provide defense in depth. These additional defenses are:

  • Least Privilege
  • White List Input Validation

Least Privilege

To minimize the potential damage of a successful SQL injection attack, you should minimize the privileges assigned to every database account in your environment. Do not assign DBA or admin type access rights to your application accounts. We understand that this is easy, and everything just ‘works’ when you do it this way, but it is very dangerous. Start from the ground up to determine what access rights your application accounts require, rather than trying to figure out what access rights you need to take away. Make sure that accounts that only need read access are only granted read access to the tables they need access to. If an account only needs access to portions of a table, consider creating a view that limits access to that portion of the data and assigning the account access to the view instead, rather than the underlying table. Rarely, if ever, grant create or delete access to database accounts.

If you adopt a policy where you use stored procedures everywhere, and don’t allow application accounts to directly execute their own queries, then restrict those accounts to only be able to execute the stored procedures they need. Don’t grant them any rights directly to the tables in the database.

SQL injection is not the only threat to your database data. Attackers can simply change the parameter values from one of the legal values they are presented with, to a value that is unauthorized for them, but the application itself might be authorized to access. As such, minimizing the privileges granted to your application will reduce the likelihood of such unauthorized access attempts, even when an attacker is not trying to use SQL injection as part of their exploit.

While you are at it, you should minimize the privileges of the operating system account that the DBMS runs under. Don’t run your DBMS as root or system! Most DBMSs run out of the box with a very powerful system account. For example, MySQL runs as system on Windows by default! Change the DBMS’s OS account to something more appropriate, with restricted privileges.

Multiple DB Users

The designer of web applications should not only avoid using the same owner/admin account in the web applications to connect to the database. Different DB users could be used for different web applications. In general, each separate web application that requires access to the database could have a designated database user account that the web-app will use to connect to the DB. That way, the designer of the application can have good granularity in the access control, thus reducing the privileges as much as possible. Each DB user will then have select access to what it needs only, and write-access as needed.

As an example, a login page requires read access to the username and password fields of a table, but no write access of any form (no insert, update, or delete). However, the sign-up page certainly requires insert privilege to that table; this restriction can only be enforced if these web apps use different DB users to connect to the database.


SQL views can further increase the granularity of access by limiting the read access to specific fields of a table or joins of tables. It could potentially have additional benefits: for example, suppose that the system is required (perhaps due to some specific legal requirements) to store the passwords of the users, instead of salted-hashed passwords. The designer could use views to compensate for this limitation; revoke all access to the table (from all DB users except the owner/admin) and create a view that outputs the hash of the password field and not the field itself. Any SQL injection attack that succeeds in stealing DB information will be restricted to stealing the hash of the passwords (could even be a keyed hash), since no DB user for any of the web applications has access to the table itself.

White List Input Validation

Input validation can be used to detect unauthorized input before it is passed to the SQL query. For more information please see the Input Validation Cheat Sheet. Proceed with caution here. Validated data is not necessarily safe to insert into SQL queries via string building.

Cookie path


The cookie path doesn’t provide any security (in most real-world situations).

It is important to understand that the cookie spec is ancient technology. It dates back from the earliest days of the web. The security model of the web has evolved since then, and become more carefully thought-out. The security model for cookies hasn’t evolved correspondingly.

As another example of impedance mismatches between the web’s security model and cookies, the same-origin policy treats as a different origin from, but they are treated as identical for purposes of cookies. You can find more discussion of security oddities with cookies from Michal Zalewski.

Cookies can be read by Javascript. While the browser may take the path into account when Javascript tries to read cookies, this is not a security feature: the path is not a security boundary, so malicious Javascript on one page can still read cookies for other paths (e.g., by opening an invisible iframe with the proper path, injecting malicious Javascript into it, and then grabbing the cookie). The only effective security boundary is at the granularity of an origin. As a result, the bottom line from a security perspective is: malicious Javascript on can read a cookie whose path is

In practice, developers typically avoid these corner cases that are left over from earlier days, or at least avoid relying upon them to provide extra security. For instance, web developers should not rely upon the cookie-path to provide security (at best it reduces the number of cookies sent back, which could perhaps be used to reduce bandwidth in some situations). As another example, sites these days usually avoid serving content from non-standard port numbers, since that situation is another corner case that exposes unexpected semantics.

At this point, the cookie path is mostly a vestigial remnant of earlier days. It doesn’t serve much purpose any longer, as far as I can tell, and if the cookie-path had never been introduced, today you’d probably never notice. But browsers still need to support it, for backwards-compatibility reasons. And so it goes, on the web. It is best to think of the web not as a carefully designed artifact but as something that evolved over time — and as a result, has accumulated now-useless gunk, like our appendix.

Session fixation

In computer network security, session fixation attacks attempt to exploit the vulnerability of a system which allows one person to fixate (set) another person’s session identifier (SID). Most session fixation attacks are web based, and most rely on session identifiers being accepted from URLs (query string) or POST data.

Attack scenarios[edit]

Alice has an account at the bank Unfortunately, Alice is not very security savvy.

Mallory is out to get Alice’s money from the bank.

Alice has a reasonable level of trust in Mallory, and will visit links Mallory sends her.

A simple attack scenario[edit]

Straightforward scenario:

  1. Mallory has determined that accepts any session identifier, accepts session identifiers from query strings and has no security validation. is thus not secure.
  2. Mallory sends Alice an e-mail: “Hey, check this out, there is a cool new account summary feature on our bank,“. Mallory is trying to fixate the SID toI_WILL_KNOW_THE_SID.
  3. Alice is interested and visits The usual log-on screen pops up, and Alice logs on.
  4. Mallory visits and now has unlimited access to Alice’s account.

Attack using server generated SID[edit]

A misconception is that servers which only accept server generated session identifiers are safe from fixation. This is false.


  1. Mallory visits and checks which SID is returned. For example, the server may respond: Set-Cookie: SID=0D6441FEA4496C2.
  2. Mallory is now able to send Alice an e-mail: “Check out this new cool feature on our bank,”
  3. Alice logs on, with fixated session identifier SID=0D6441FEA4496C2.

Attacks using cross-site cooking[edit]

Another session fixation attack, cross-site cooking, exploits browser vulnerabilities. This allows the site to store cookies in Alice’s browser in the cookie domain of another server, which is trusted. This attack can succeed even when there is no vulnerability within, because may assume that browser cookie management is secure.


  1. Mallory sends Alice an e-mail: “Hey, check out this cool site,“.
  2. Alice visits, which sets the cookie SID with the value I_WILL_KNOW_THE_SID into the domain of
  3. Alice doesn’t know that the SID was fixed to Mallory’s content, and logs into later in the day. Mallory can now use her account using the fixated session identifier.

Attacks using cross-subdomain cooking[edit]

This is like cross-site cooking, except that it does not rely on browser vulnerabilities. Rather, it relies on the fact that wildcard cookies can be set by one subdomain that affect other subdomains.


  1. A web site hands out subdomains to untrusted third parties
  2. One such party, Mallory, who now controls, lures Alice to her site
  3. A visit to sets a session cookie with the domain on Alice’s browser
  4. When Alice visits, this cookie will be sent with the request, as the specs for cookies states, and Alice will have the session specified by Mallory’s cookie.
  5. If Alice now logs on, Mallory can use her account.

Each of these attack scenarios has resulted in Cross-calation, where Mallory has successfully gained access to the functions and data normally reserved for Alice.

An alternate attack scenario does not require Alice to log in to a site. Rather, simply by fixing the session, Mallory may be able to spy on Alice and abuse the data she enters. For example, Mallory may use the above attacks to give Alice her own authenticated session—so Alice will start using the site with all the authentication of Mallory. If Alice decides to purchase something on this site and enters her credit card details, Mallory might be able to retrieve that data (or other confidential data) by looking through the historical data stored for the account.


Do not accept session identifiers from GET / POST variables[edit]

Session identifiers in URL (query string, GET variables) or POST variables are not recommended as they simplify this attack – it is easy to make links or forms which set GET / POST variables.

Additionally, session identifiers (SIDs) in query strings enable other risk and attack scenarios;

  • The SID is leaked to others servers through the Referrer
  • The SID is leaked to other people as users cut & paste “interesting links” from the address bar into chat, forums, communities, etc.
  • The SID is stored in many places (browser history log, web server log, proxy logs, …)

Note: Cookies are shared between tabs and popped up browser windows. If your system requires to be hit with the same domain ( and ), cookies may conflict with one another between tabs.

It may be required to send the session identifier on the URL in order to overcome this limitation. If possible use or so there is no domain conflicts in the cookies. This may incur costs with extra SSL certificates.

This behavior can be seen on many sites by opening another tab and trying to do side by side search results. One of the sessions will become unusable.

Best solution: Identity Confirmation[edit]

This attack can be largely avoided by changing the session ID when users log in. If every “important” request requires the user to be authenticated with (“logged into”) the site, an attacker would need to know the id of the victim’s log-in session. When the victim visits the link with the fixed session id, however, they will need to log into their account in order to do anything “important” as themselves. At this point, their session id will change and the attacker will not be able to do anything “important”.

A similar technique can be used to solve the phishing problem. If the user protects their account with two passwords, then it can be solved to a great extent.

Solution: Store session identifiers in HTTP cookies[edit]

The session identifier on most modern systems is stored by default in an HTTP cookie, which has a moderate level of security as long as the session system disregards GET/POST values.[citation needed] However, this solution is vulnerable to cross-site request forgery.

Solution: Utilize SSL / TLS Session identifier[edit]

When enabling HTTPS security, some systems allow applications to obtain the SSL / TLS session identifier. Use of the SSL/TLS session identifier is very secure, but many web development languages do not provide robust built-in functionality for this.

SSL/TLS session identifiers may be suitable only for critical applications, such as those on large financial sites, due to the size of the systems. This issue, however, is rarely debated even in security forums.[citation needed]

Regenerate SID on each request[edit]

A countermeasure against session fixation is to generate a new session identifier (SID) on each request. If this is done, then even though an attacker may trick a user into accepting a known SID, the SID will be invalid when the attacker attempts to re-use the SID. Implementation of such a system is simple, as demonstrated by the following:

  • Get previous Session Identifier OLD_SID from HTTP request.
  • If OLD_SID is null, empty, or no session with SID=OLD_SID exists, create a new session.
  • Generate new session identifier NEW_SID with a secure random number generator.
  • Let session be identified by SID=NEW_SID (and no longer by SID=OLD_SID)
  • Transmit new SID to client.


If Mallory successfully tricks Alice into visiting, this HTTP request is sent to

Host: accepts SID=I_KNOW_THE_SID, which is bad. However, is secure because it performs session regeneration. gets the following response:

HTTP/1.1 200 OK
Set-Cookie: SID=3134998145AB331F

Alice will now use SID=3134998145AB331F which is unknown to Mallory, and SID=I_KNOW_THE_SID is invalid. Mallory is thus unsuccessful in the session fixation attempt.

Unfortunately session regeneration is not always possible. Problems are known to occur when third-party software such as ActiveX or Java Applets are used, and when browser plugins communicate with the server. Third-party software could cause logouts, or the session could be split into two separate sessions.

If the implementation of sessions includes transmitting the SID through GET or POST variables, then this might also render the “back” button in most browsers unusable, as the user would the be using and older, invalid, session identifier from a previous request.

Accept only server-generated SIDs[edit]

One way to improve security is not to accept session identifiers that were not generated by the server. However, as noted above, this does not prevent all session fixation attacks.

   session_destroy(); // destroy all data in session
session_regenerate_id(); // generate a new session identifier

Logout function[edit]

A logout function is useful as it allows users to indicate that a session should not allow further requests. Thus attacks can only be effective while a session is active. Note that the following code performs no Cross-site request forgerychecks, potentially allowing an attacker to force users to log out of the web application.

if ( logout ))
   session_destroy(); // destroy all data in session

Time-out old SIDs[edit]

This defense is simple to implement and has the advantage of providing a measure of protection against unauthorized users accessing an authorized user’s account by using a machine that may have been left unattended.

Store a session variable containing a time stamp of the last access made by that SID. When that SID is used again, compare the current timestamp with the one stored in the session. If the difference is greater than a predefined number, say 5 minutes, destroy the session. Otherwise, update the session variable with the current timestamp.

Destroy session if Referrer is suspicious[edit]

When visiting a page, most browsers will set the Referrer – the page that contained the link that you followed to get to this page.

When the user is logged into a site that is not likely to be linked to from outside that site (e.g., banking websites, or webmail), and the site is not the kind of site where users would remain logged in for any great length of time, the Referrer should be from that site. Any other Referrer should be considered suspicious. However, if the originating request is from a HTTPS page, then the referrer will be stripped, so you cannot depend on this security system.

For example, could employ the following security check:

if (strpos($_SERVER['HTTP_REFERER'], '') !== 0) {
   session_destroy(); // destroy all data in session
session_regenerate_id(); // generate a new session identifier

Verify that additional information is consistent throughout session[edit]

One way to further improve security is to ensure that the user appears to be the same end user (client). This makes it a bit harder to perform session fixation and other attacks.

As more and more networks begin to conform to RFC 3704 and other anti-spoofing practices, the IP address becomes more reliable as a “same source” identifier. Therefore, the security of a web site can be improved by verifying that the source IP is consistent throughout a session.

This could be performed in this manner:

   session_destroy(); // destroy all data in session
session_regenerate_id(); // generate a new session identifier

However, there are some points to consider before employing this approach.

  • Several users may share one IP. It is not uncommon for an entire building to share one IP using NAT.
  • One user may have an inconsistent IP. This is true for users behind proxies (such as AOL customers). It is also true for some mobile/roaming users, as well as users that are behind load balanced Internet connections. Users with IPv6 Privacy Extensions enabled may also change their IPv6 privacy addresses at any time.

For some sites, the added security outweighs the lack of convenience, and for others it does not.

User Agent[edit]

Browsers identify themselves by “User-Agent” HTTP headers. This header does not normally change during use; it would be extremely suspicious if that were to happen. A web application might make use of User-Agent detection in attempt to prevent malicious users from stealing sessions. This however is trivial to bypass, as an attacker can easily capture the victim’s user-agent with their own site and then spoof it during the attack. This proposed security system is relying on Security through obscurity.

   session_destroy(); // destroy all data in session
session_regenerate_id(); // generate a new session identifier

However, there are some points to consider before employing this approach.

  • Several users may have same browser User Agent in Internet café.
  • Several users may have same default browser (ex: Internet Explorer 6 in Windows XP SP3 or mini browser in mobile phone).

But User Agent may change legally in few cases. Following examples are the same users. For example MSIE may change the UA string based on compatibility mode:

  • Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 Build/VZW) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 854X480 motorola DROID2
  • Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 Build/VZW) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 480X854 motorola DROID2
  • Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
  • Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)

Defense in Depth[edit]

Defense in depth is to combine several countermeasures. The idea is simple: if one obstacle is trivial to overcome, several obstacles could be very hard to overcome.

A Defence in Depth strategy could involve:

  • Enable HTTPS (to protect against other problems)
  • Correct configuration (do not accept external SIDs, set time-out, etc.)
  • Perform session_regeneration, support log-out, etc.

It should be noted that HTTP referers are not passed with SSL.

The following PHP script demonstrates several such countermeasures combined in a Defence in Depth manner:

if (isset($_GET['LOGOUT']) ||

session_regenerate_id(); // generate a new session identifier


Note that this code checks the current REMOTE_ADDR (the user’s IP address) and User-agent against the REMOTE_ADDR and User-agent of the previous request. This might be inconvenient for some sites as discussed above.


Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet




Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious Web site, email, blog, instant message, or program causes a user’s Web browser to perform an unwanted action on a trusted site for which the user is currently authenticated. The impact of a successful cross-site request forgery attack is limited to the capabilities exposed by the vulnerable application. For example, this attack could result in a transfer of funds, changing a password, or purchasing an item in the user’s context. In affect, CSRF attacks are used by an attacker to make a target system perform a function (funds Transfer, form submission etc.) via the target’s browser without knowledge of the target user, at least until the unauthorized function has been committed.

Impacts of successful CSRF exploits vary greatly based on the role of the victim. When targeting a normal user, a successful CSRF attack can compromise end-user data and their associated functions. If the targeted end user is an administrator account, a CSRF attack can compromise the entire Web application. The sites that are more likely to be attacked are community Websites (social networking, email) or sites that have high dollar value accounts associated with them (banks, stock brokerages, bill pay services). This attack can happen even if the user is logged into a Web site using strong encryption (HTTPS). Utilizing social engineering, an attacker will embed malicious HTML or JavaScript code into an email or Website to request a specific ‘task url’. The task then executes with or without the user’s knowledge, either directly or by utilizing a Cross-site Scripting flaw (ex: Samy MySpace Worm).

For more information on CSRF, please see the OWASP Cross-Site Request Forgery (CSRF) page.

Prevention Measures That Do NOT Work

Using a Secret Cookie

Remember that all cookies, even the secret ones, will be submitted with every request. All authentication tokens will be submitted regardless of whether or not the end-user was tricked into submitting the request. Furthermore, session identifiers are simply used by the application container to associate the request with a specific session object. The session identifier does not verify that the end-user intended to submit the request.

Only Accepting POST Requests

Applications can be developed to only accept POST requests for the execution of business logic. The misconception is that since the attacker cannot construct a malicious link, a CSRF attack cannot be executed. Unfortunately, this logic is incorrect. There are numerous methods in which an attacker can trick a victim into submitting a forged POST request, such as a simple form hosted in an attacker’s Website with hidden values. This form can be triggered automatically by JavaScript or can be triggered by the victim who thinks the form will do something else.

Multi-Step Transactions

Multi-Step transactions are not an adequate prevention of CSRF. As long as an attacker can predict or deduce each step of the completed transaction, then CSRF is possible.

URL Rewriting

This might be seen as a useful CSRF prevention technique as the attacker can not guess the victim’s session ID. However, the user’s credential is exposed over the URL.

General Recommendation: Synchronizer Token Pattern

In order to facilitate a “transparent but visible” CSRF solution, developers are encouraged to adopt the Synchronizer Token Pattern ( The synchronizer token pattern requires the generating of random “challenge” tokens that are associated with the user’s current session. These challenge tokens are the inserted within the HTML forms and links associated with sensitive server-side operations. When the user wishes to invoke these sensitive operations, the HTTP request should include this challenge token. It is then the responsibility of the server application to verify the existence and correctness of this token. By including a challenge token with each request, the developer has a strong control to verify that the user actually intended to submit the desired requests. Inclusion of a required security token in HTTP requests associated with sensitive business functions helps mitigate CSRF attacks as successful exploitation assumes the attacker knows the randomly generated token for the target victim’s session. This is analogous to the attacker being able to guess the target victim’s session identifier. The following synopsis describes a general approach to incorporate challenge tokens within the request.

When a Web application formulates a request (by generating a link or form that causes a request when submitted or clicked by the user), the application should include a hidden input parameter with a common name such as “CSRFToken”. The value of this token must be randomly generated such that it cannot be guessed by an attacker. Consider leveraging the class for Java applications to generate a sufficiently long random token. Alternative generation algorithms include the use of 256-bit BASE64 encoded hashes. Developers that choose this generation algorithm must make sure that there is randomness and uniqueness utilized in the data that is hashed to generate the random token.

  <form action="/" method="post">
  <input type="hidden" name="CSRFToken" value="OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZjMTVi

In general, developers need only generate this token once for the current session. After initial generation of this token, the value is stored in the session and is utilized for each subsequent request until the session expires. When a request is issued by the end-user, the server-side component must verify the existence and validity of the token in the request as compared to the token found in the session. If the token was not found within the request or the value provided does not match the value within the session, then the request should be aborted, token should be reset and the event logged as a potential CSRF attack in progress.

To further enhance the security of this proposed design, consider randomizing the CSRF token parameter name and or value for each request. Implementing this approach results in the generation of per-request tokens as opposed to per-session tokens. Note, however, that this may result in usability concerns. For example, the “Back” button browser capability is often hindered as the previous page may contain a token that is no longer valid. Interaction with this previous page will result in a CSRF false positive security event at the server. Regardless of the approach taken, developers are encouraged to protect the CSRF token the same way they protect authenticated session identifiers, such as the use of SSLv3/TLS.

Disclosure of Token in URL

Many implementations of this control include the challenge token in GET (URL) requests as well as POST requests. This often implemented as a result of sensitive server-side operations being invoked as a result of embedded links in the page or other general design patterns. These patterns are often implemented without knowledge of CSRF and an understanding of CSRF prevention design strategies. While this control does help mitigate the risk of CSRF attacks, the unique per-session token is being exposed for GET requests. CSRF tokens in GET requests are potentially leaked at several locations: browser history, HTTP log files, network appliances that make a point to log the first line of an HTTP request, and Referrer headers if the protected site links to an external site.

In the latter case (leaked CSRF token due to the Referer header being parsed by a linked site), it is trivially easy for the linked site to launch a CSRF attack on the protected site, and they will be able to target this attack very effectively, since the Referer header tells them the site as well as the CSRF token. The attack could be run entirely from javascript, so that a simple addition of a script tag to the HTML of a site can launch an attack (whether on an originally malicious site or on a hacked site). Timeouts on CSRF tokens are very unlikely to help this attack scenario.

The ideal solution is to only include the CSRF token in POST requests and modify server-side actions that have state changing affect to only respond to POST requests. This is in fact what the RFC 2616 requires for GET requests. If sensitive server-side actions are guaranteed to only ever respond to POST requests, then there is no need to include the token in GET requests.

In most JavaEE web applications, however, HTTP method scoping is rarely ever utilized when retrieving HTTP parameters from a request. Calls to “HttpServletRequest.getParameter” will return a parameter value regardless if it was a GET or POST. This is not to say HTTP method scoping cannot be enforced. It can be achieved if a developer explicitly overrides doPost() in the HttpServlet class or leverages framework specific capabilities such as the AbstractFormController class in Spring.

For these cases, attempting to retrofit this pattern in existing applications requires significant development time and cost, and as a temporary measure it may be better to pass CSRF tokens in the URL. Once the application has been fixed to respond to HTTP GET and POST verbs correctly, CSRF tokens for GET requests should be turned off.

Viewstate (ASP.NET)

ASP.NET has an option to maintain your ViewState. The ViewState indicates the status of a page when submitted to the server. The status is defined through a hidden field placed on each page with a <form runat=”server”> control. Viewstate can be used as a CSRF defense, as it is difficult for an attacker to forge a valid Viewstate. It is not impossible to forge a valid Viewstate since it is feasible that parameter values could be obtained or guessed by the attacker. However, if the current session ID is added to the ViewState, it then makes each Viewstate unique, and thus immune to CSRF.

To use the ViewStateUserKey property within the Viewstate to protect against spoofed post backs. Add the following in the OnInit virtual method of the Page-derived class (This property must be set in the Page.Init event)

  protected override OnInit(EventArgs e) {
     if (User.Identity.IsAuthenticated)
        ViewStateUserKey = Session.SessionID; }

The following keys the Viewstate to an individual using a unique value of your choice.


This must be applied in Page_Init because the key has to be provided to ASP.NET before Viewstate is loaded. This option has been available since ASP.NET 1.1.

However, there are limitations on this mechanism. Such as, ViewState MACs are only checked on POSTback, so any other application requests not using postbacks will happily allow CSRF.

Double Submit Cookies

Double submitting cookies is defined as sending the session ID cookie in two different ways for every form request. First as a traditional header value, and again as a hidden form value. When a user visits a site, the site should generate a (cryptographically strong) pseudorandom value and set it as a cookie on the user’s machine. This is typically referred to as the session ID. The site should require every form submission to include this pseudorandom value as a hidden form value and also as a cookie value. When a POST request is sent to the site, the request should only be considered valid if the form value and the cookie value are the same. When an attacker submits a form on behalf of a user, he can only modify the values of the form. An attacker cannot read any data sent from the server or modify cookie values, per the same-origin policy. This means that while an attacker can send any value he wants with the form, the attacker will be unable to modify or read the value stored in the cookie. Since the cookie value and the form value must be the same, the attacker will be unable to successfully submit a form unless he is able to guess the session ID value.

While this approach is effective in mitigating the risk of cross-site request forgery, including authenticated session identifiers in HTTP parameters may increase the overall risk of session hijacking. Architects and developers must ensure that no network appliances or custom application code or modules explicitly log or otherwise disclose HTTP POST parameters. An attacker that is able to obtain access to repositories or channels that leak HTTP POST parameters will be able to replay the tokens and perform session hijacking attacks. Note, however, that transparently logging all HTTP POST parameters is a rare occurrence across network systems and web applications as doing so will expose significant sensitive data aside from session identifiers including passwords, credit card numbers, and or social security numbers. Inclusion of the session identifier within HTML can also be leveraged by cross-site scripting attacks to bypass HTTPOnly protections. Most modern browsers prevent client-side script from accessing HTTPOnly cookies. However, this protection is lost if HTTPOnly session identifiers are placed within HTML as client-side script can easily traverse and extract the identifier from the DOM. Developers are still encouraged to implement the synchronizer token pattern as described in this article.

Direct Web Remoting (DWR) Java library version 2.0 has CSRF protection built in as it implements the double cookie submission transparently.

Prevention Frameworks

There are CSRF prevention modules available for J2EE, .Net, and PHP.

OWASP CSRF Guard (For Java)

The OWASP CSRFGuard Project makes use of a unique per-session token verification pattern using a JavaEE filter to mitigate the risk of CSRF attacks. When an HttpSession is first instantiated, CSRFGuard will generate a cryptographically random token using the SecureRandom class to be stored in the session.

Similar Projects

CSRFGuard has been implemented in other languages besides Java. They are:


Challenge-Response is another defense option for CSRF. The following are some examples of challenge-response options.

  • Re-Authentication (password)
  • One-time Token

While challenge-response is a very strong defense to CSRF (assuming proper implementation), it does impact user experience. For applications in need of high security, tokens (transparent) and challenge-response should be used on high risk functions.

Checking The Referer Header

Although it is trivial to spoof the referer header on your own browser, it is impossible to do so in a CSRF attack. Checking the referer is a commonly used method of preventing CSRF on embedded network devices because it does not require a per-user state. This makes a referer a useful method of CSRF prevention when memory is scarce.

However, checking the referer is considered to be a weaker from of CSRF protection. For example, open redirect vulnerabilities can be used to exploit GET-based requests that are protected with a referer check. It should be noted that GET requests should never incur a state change as this is a violation of the HTTP specification.

There are also common implementation mistakes with referer checks. For example if the CSRF attack originates from an HTTPS domain then the referer will be omitted. In this case the lack of a referer should be considered to be an attack when the request is performing a state change. Also note that the attacker has limited influence over the referer. For example, if the victim’s domain is “” then an attacker have the CSRF exploit originate from “” which may fool a broken referer check implementation. XSS can be used to bypass a referer check.

Checking The Origin Header

The Origin HTTP Header was introduced as a method of defending against CSRF and other Cross-Domain attacks. Unlike the referer, the origin will be present in HTTP request that originates from an HTTPS url.

If the origin header is present, then it should be checked for consistency.

Client/User Prevention

Since CSRF vulnerabilities are reportedly widespread, it is recommended to follow best practices to mitigate risk. Some mitigating include:

  • Logoff immediately after using a Web application
  • Do not allow your browser to save username/passwords, and do not allow sites to “remember” your login
  • Do not use the same browser to access sensitive applications and to surf the Internet freely (tabbed browsing).
  • The use of plugins such as No-Script makes POST based CSRF vulnerabilities difficult to exploit. This is because JavaScript is used to automatically submit the form when the exploit is loaded. Without JavaScript the attacker would have to trick the user into submitting the form manually.

Integrated HTML-enabled mail/browser and newsreader/browser environments pose additional risks since simply viewing a mail message or a news message might lead to the execution of an attack.

No Cross-Site Scripting (XSS) Vulnerabilities

Cross-Site Scripting is not necessary for CSRF to work. However, any cross-site scripting vulnerability can be used to defeat token, Double-Submit cookie, referer and origin based CSRF defenses. This is because an XSS payload can simply read any page on the site using a XMLHttpRequest and obtain the generated token from the response, and include that token with a forged request. This technique is exactly how the MySpace (Samy) worm defeated MySpace’s anti CSRF defenses in 2005, which enabled the worm to propagate. XSS cannot defeat challenge-response defenses such as Captcha, re-authentication or one-time passwords. It is imperative that no XSS vulnerabilities are present to ensure that CSRF defenses can’t be circumvented. Please see the OWASP XSS Prevention Cheat Sheet for detailed guidance on how to prevent XSS flaws.