Today, most security breaches online occur through the application rather than the server. The majority of web application attacks occur through cross-site scripting (XSS) and SQL injection attacks which typically result from flawed coding, and failure to sanitize input to and output from the web application.
In this blog I will be discussing these two attacks and methods on how to counter them.
Cross Site Scripting (XSS)
Cross-site scripting (XSS) is an injection attack which is carried out on Web applications that accept input, but do not properly separate data and executable code before the input is delivered back to a user’s browser.
Cross-site scripting (XSS) attacks, bypass the same origin policy by tricking a site into delivering malicious code along with the intended content. This is a huge problem, as browsers trust all of the code that shows up on a page as being legitimately part of that page’s security origin.
Same Origin Policy requires everything on a Web page to come from the same source. When Same Origin Policy is not enforced, an attacker might inject a script and modify the Web page to suit his own purposes, perhaps to extract data that will allow the attacker to impersonate an authenticated user or perhaps to input malicious code for the browser to execute.
There are a number of security controls that can be used to reduce or entirely remove the threat of cross-site scripting. They include:
- Input validation – determines if an end user’s input matches the expected format. For example, a browser-side script would not be expected in a phone number field.
- Content Security Policy (CSP) – restricts which scripts can be run or loaded on a Web page.
- Output encoding – tells the browser that certain characters it is going to receive should be treated as display text, rather than executable code.
Play provides security headers filter that can be used to configure some default headers in the HTTP response to mitigate security issues. The ContentSecurity-Policy HTTP response header helps you reduce XSS risks on modern browsers by declaring what dynamic resources are allowed to load via a HTTP Header.
Configuring Security Headers
- Enabling the security headers filterTo enable the security headers filter, add the Play filters project to your libraryDependencies in build.sbt:
libraryDependencies += filters
Now add the security headers filter to your filters, which is typically done by creating a Filters class in the root of your project:
import javax.inject.Inject import play.api.http.DefaultHttpFilters import play.filters.headers.SecurityHeadersFilter class Filters @Inject() (securityHeadersFilter: SecurityHeadersFilter) extends DefaultHttpFilters(securityHeadersFilter)
The Filters class can either be in the root package, or if it has another name or is in another package, needs to be configured using play.http.filters in application.conf:
play.http.filters = "filters.MyFilters"
Configuring the security headers
The filter will set headers in the HTTP response automatically. The settings can be configured through the following settings in application.conf
- play.filters.headers.frameOptions – sets X-Frame-Options, “DENY” by default.
- play.filters.headers.xssProtection – sets X-XSS-Protection, “1; mode=block” by default.
- play.filters.headers.contentTypeOptions – sets X-Content-Type-Options, “nosniff” by default.
- play.filters.headers.permittedCrossDomainPolicies – sets X-Permitted-Cross-Domain-Policies, “master-only” by default.
- play.filters.headers.contentSecurityPolicy – sets Content-Security-Policy, “default-src ‘self’” by default.
Any of the headers can be disabled by setting a configuration value of null, for example:
play.filters.headers.frameOptions = null
The Content-Security-Policy HTTP header allows you to create a whitelist of sources of trusted content, and instructs the browser to only execute or render resources from those sources.
CSP provides a rich set of policy directives that control over the resources that a page is allowed to load.
- base-uri restricts the URLs that can appear in page’s <base> element.
- child-src lists the URLs for workers and embedded frame contents. For example: child-src https://youtube.com would enable embedding videos from YouTube but not from other origins. Use this in place of the deprecated frame-src directive.
- connect-src limits the origins to which you can connect (via XHR, WebSockets, and EventSource).
- font-src specifies the origins that can serve web fonts. Google’s Web Fonts could be enabled via font-src https://themes.googleusercontent.com
- form-action lists valid endpoints for submission from <form> tags.
- frame-ancestors specifies the sources that can embed the current page. This directive applies to <frame>, <iframe>, , and <applet>tags. This directive cant be used in <meta> tags and applies only to non-HTML resources.
- frame-src deprecated. Use child-src instead.
- img-src defines the origins from which images can be loaded.
- media-src restricts the origins allowed to deliver video and audio.
- object-src allows control over Flash and other plugins.
- plugin-types limits the kinds of plugins a page may invoke.
- report-uri specifies a URL where a browser will send reports when a content security policy is violated. This directive cant be used in <meta> tags.
- style-src is script-src’s counterpart for stylesheets.
- upgrade-insecure-requests Instructs user agents to rewrite URL schemes, changing HTTP to HTTPS. This directive is for web sites with large numbers of old URLs that need to be rewritten.
default-src directive defines the defaults for most directives you leave unspecified. Generally, this applies to any directive that ends with -src. If default-src is set to https://example.com, and you fail to specify a font-src directive, then you can load fonts from https://example.com, and nowhere else.
Suppose we have a project in which we want to load an image from some other domain but as we have set the CSP header to self we are only allowed to load the images from the same domain.
So in this case we can use the img-src directive and set its value as
play.filters.headers.contentSecurityPolicy = "default-src 'self'; img-src 'self' www.gettyimages.ca"
where http://www.gettyimages.ca is the other domain from where to load the image.
SQL injection is a type of security exploit in which the attacker adds Structured Query Language (SQL) code to a Web form input box to gain access to resources or make changes to data. An SQL query is a request for some action to be performed on a database. Typically, on a Web form for user authentication, when a user enters their name and password into the text boxes provided for them, those values are inserted into a SELECT query. If the values entered are found as expected, the user is allowed access; if they aren’t found, access is denied. However, most Web forms have no mechanisms in place to block input other than names and passwords. Unless such precautions are taken, an attacker can use the input boxes to send their own request to the database, which could allow them to download the entire database or interact with it in other illicit ways.
Imagine a simple Web site set up by a package delivery company to provide delivery status information to anyone who knows the tracking number associated with a particular package. The application may simply ask the user for the tracking number and then look it up in a database table using the following SQL code:
SELECT * FROM Shipments WHERE TrackingID='@tracking'
Where @tracking is a variable passed in from the Web application. Under normal circumstances, this application may function perfectly normally. For example, if a user enters the tracking number 1A2123ZC2, the corresponding query would be:
SELECT * FROM Shipments WHERE TrackingID='1A2123ZC2'
That ideal situation makes one flawed assumption — that the user will only enter a valid tracking number. Malicious individuals are not likely to be so cooperative. Suppose that the user instead enters the string shown below in the tracking number field:
1A2123ZC2′ or true
The corresponding query will now be:
SELECT * FROM Shipments WHERE TrackingID='1A2123ZC2' or true
Which will have the unintended consequence of retrieving all of the tracking information stored in the database. Now assume that we have an even more malicious user who enters the following string:
1A2123ZC2′; DELETE FROM Shipments
This would cause the database to execute the following query:
SELECT * FROM Shipments WHERE TrackingID='1A2123ZC2'; DELETE FROM Shipments
Which would have the clearly undesirable result of deleting all of the tracking information from the database!
There are several steps that you can take to reduce the possibility of a SQL injection attack against your database:
- Escape single quotation marks. Include code within your Web applications that replaces single apostrophes with double apostrophes. This will force the database server to recognize the apostrophe as a literal character rather than a string delimiter.
- Limit the privileges available to the account that executes Web application code. In the example above, if the account only had permission to perform the intended action (retrieving records from the Shipping table), the deletion would not be possible.
- Reduce or eliminate debugging information. When an error condition occurs on your server, the Web user should not see technical details of the error. This type of information could aid an intruder seeking to explore the structure of your database.
Here is the link of the github repository for the XSS example: