Non-HTTP protocol related vulnerabilites:
- XSS
- Clickjacking
- Man-in-The-Middle
HTTP is a stateless application level protocol for distributed, collaborative, hypertext information systems.
Working OSI (Open Systems Interconnection) Model:
- Physical Layer
- Data Link Layer
- Network Layer
- Transport Layer
- Session Layer
- Presentation Layer
- Application Layer
GET /courses HTTP/1.1
Host: codebashing.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36
Referer: https://codebashing.com/
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ru;q=0.8
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Connection: close
- GET is an HTTP verb used to retrieve data from a server
/courses
is a path where the desired data residesHTTP/1.1
is the HTTP protocol version that is used for communicationHOST
header specifies the requested hostname (authority part of the URL).User-Agent
header describes the software used to make a request.Referer
header contains a previous page visited by the user.Accept
andAccept-*
headers specify the type of the content, language, encoding, etc. that a client understandsCache-control
header defines cache mechanism behaviorUpgrade-Insecure-Requests
header shows to the server that the client prefers encrypted communicationsConnection
header defines whether the network connection should stay open
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Server: nginx/1.11.9
X-Frame-Options: ALLOW-FROM https://academy.checkmarx.net
ETag: W/"8ca5dd4f507a4295e629491c"
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: trackingCookie=user1357272
X-Request-Id: 295e586f-7cab-4530-b5cb-1c
X-Runtime: 0.2243
Connection: close
Content-Length: 8576
<!DOCTYPE html>
<-- Web Page content -->
Content-Type
header defines the type of content that resides in the response bodyServer
header describes the software that is running on the server sideX-Frame-Options
defines domains that can open pages from the current domain in the or similar HTML tagsETag
andCache-Control
headers are used to manage caching.Set-Cookie
header instructs the user-agent to save header directives as cookies.X-Request-Id
andX-Runtime
are custom headers that are specific to the application or environment where the application is hosted.Connection
header defines whether the network connection should stay open.Content-Length
defines the length of the response body.
POST /login HTTP/1.1
Host: www.lotsofgoods.me
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36
Referer: https://codebashing.com/
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Connection: close
Content-Length: 46
login=alice&password=correcthorsebatterystaple
POST
is an HTTP verb used to send data to the server and change the application state/login
is the URL path
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Server: nginx/1.11.9
ETag: W/"d18a59b032422092a1daaccd9b46bbf4"
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: sessionid=26161af57b9de30f9b67d16be83700113f8742a136c26d3d2e90b677b85934fe
Connection: close
Content-Length: 1467
<!DOCTYPE html>
<-- Web Page content -->
Once implemented, HTTP security headers restrict modern browsers from running into easily preventable vulnerabilities. They also provide yet another, additional layer of security by helping to mitigate security vulnerabilities and prevent attacks (like XSS, Clickjacking, information leakage, etc.). But it is important to mention that HTTP security headers are not intended to replace proper, secure code.
HTTP/1.1 200 OK
Date: Thu, 21 Mar 2019 09:05:07 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Connection: close
Cache-Control: max-age=600
Content-Security-Policy: script-src 'self' *.codebashing.com 'unsafe-inline' 'unsafe-eval' www.google-analytics.com; img-src 'self' *.codebashing.com
Expires: Thu, 21 Mar 2019 09:15:06 GMT
Location: https://codebashing.com
strict-transport-security: max-age=31536000
Vary: Accept-Language, Accept-Encoding
x-content-type-options: nosniff
X-Frame-Options: DENY
X-Robots-Tag: noodp
x-xss-protection: 1; mode=block
HTTP Strict Transport Security (HSTS) is a mechanism that prevents user-agents (a browser or any kind of program designed for communication with a particular server) from browsing a website via an unencrypted connection in case an encrypted connection can be established, and only using a trusted certificate.
If the request is communicated through an unencrypted channel, it can be captured and tampered with by an attacker. The attacker then can steal or modify any information transmitted between the client and the server or redirect the user to a phishing website. So, the first goal of HSTS is to ensure traffic is encrypted, so it instructs the browser to always use HTTPS instead of HTTP.
Usually, browsers allow users to ignore TLS errors and continue browsing potentially insecure websites. With HSTS enabled, the user will be unable to skip the browser warning and continue. The second important goal of HSTS is to make sure that the traffic is encrypted using a trusted and valid certificate.
When HSTS response header signals the browser that the certain domain must be requested only using HTTPS, the browser saves this domain to the HSTS list and keeps it there for the timeframe specified in max-age directive of the Strict-Transport-Security header. There are two cases when HSTS doesn't provide proper protection:
- when the user hasn't browsed to the website before and is making his very first request to this website over HTTP,
- when existing HSTS data has already expired.
To resolve this, it is possible to have a domain included in the HSTS preload list which arrives baked into most modern browsers.
Some modern browsers have built-in XSS protection mechanisms that can be used as an additional layer of security against Reflected XSS. The main problem with that is that all of the browsers implement built-in XSS filtering differently, so to add more control to the process and make sure that the loading of a page with the malicious content will be blocked, the X-XSS-Protection header is needed.
X-XSS-Protection header is an optional HTTP header that performs XSS filtering by defining the anti-XSS mechanism behavior: from sanitizing the page by blocking injected Javascript to preventing page rendering and reporting the violation.
By default, browsers that support XSS filtering have it enabled. Though it can be disabled, this is considered a bad practice; often, if an application requires XSS protection to be disabled in order to function properly, it is an indication that the application is quite likely vulnerable to XSS.
Please note that only using the X-XSS-Protection header will not protect your application from XSS, but this header will make an important input in your defense-in-depth strategy and make it more robust.
X-Frame-Options header a defines if the webpage can be rendered inside an <iframe>, , , or tags. Depending on the directive, this header either specifies the list of domains that can embed the webpage, or allows the page to be embedded only inside pages of the same origin, or totally prohibits embedding of a webpage.
The main purpose of the X-Frame-Options header is to protect against Clickjacking. Clickjacking is an attack when the vulnerable page is loaded in a frame inside the malicious page, and the users are tricked into interaction with buttons and other clickable UI elements (e.g. unknowingly clicking "likes" or downloading malicious files) of a vulnerable page without their knowledge.
(Note that setting X-Frame-Options with HTML tag inside a webpage doesn't work. Use HTTP headers to set it.)
In the right pane, you can see a screenshot of the webpage where the content of another page was denied to be displayed in a frame because the X-Frame-Options header disallowed the browser from doing so with a deny directive.
X-Frame-Options is also covered by Content-Security-Policy (CSP). CSP is a suite of headers with security directives for multiple uses (which will be covered in their own lesson). Among these security directives is the frame-ancestorsdirective which pursues the same goal as the X-Frame-Options header. The main difference between them is the implementation of the SAMEORIGIN directive of the X-Frame-Options header.
Various user-agents interpret SAMEORIGIN directive in a different way, and some of them only check the top-level domain. Whereas with the CSP's frame-ancestors directive, the whole chain of origins is checked. (The example of the chain of origins is an iframe inside an iframe, inside an iframe, and so on.)
The CSP W3C recommendation states that with the CSP frame-ancestors directive being introduced, the X-Frame-Options header becomes obsolete. Thus CSP should be used to prevent Clickjacking in the first place and the X-Frame-Options header should be used for backward compatibility with browsers that don't support this CSP directive.
When HTTP v1.1 is used in HTTP requests, it presents them in a human-readable format. HTTP v2 requests are binary and require special tools to be read. The main difference between v1.1. and v2 is the way requests and responses are transmitted: HTTP2 is aimed at decreasing the time required for data transfer.
GET /courses HTTP/1.1
Host: codebashing.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36
Origin: https://codebashing.com
Referer: https://codebashing.com/dashboard
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ru;q=0.8
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Cookie: sessionid=b3cd288f3e3d499ca8e45fbae696f7b5
Connection: close
HTTP/1.1 200 OK
Date: Sat, 08 March 2019 12:33:14 GMT
Server: nginx/1.11.9
X-Frame-Options: ALLOW-FROM https://academy.checkmarx.net
ETag: W/"8ca5dd4f507a4295e629491c"
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: trackingCookie=user135727
X-Request-Id: 295e586f-7cab-4530-b5cb-1c
X-Runtime: 0.2243
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 8576
<!DOCTYPE html>
<-- Web Page content -->
In HTTP v1.1 and v2 the following methods are used for different purposes: GET, POST, HEAD, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH.
The most used of them are GET and POST methods.
GET method is used to retrieve data from a server. GET requests are read-only (according to the HTTP RFC, they should not change the application state but in real life they sometimes do) and do not have a body.
POST requests are used to change the application state and have a body.
Using GET for state-changing operations can lead to CSRF and information disclosure. First, because GET request doesn’t have a body, all the information is sent in an URL, and the URL can be disclosed in intermediate devices. Second, for POST requests, there is built-in protection against CSRF in all modern frameworks, but for GET requests, it depends on the framework, whether or not it has built-in CSRF protection for them.
Description of other HTTP methods could be found under the following links:
https://tools.ietf.org/html/rfc7231 and https://tools.ietf.org/html/rfc5789
POST /login HTTP/1.1
Host: lotsofgoods.me
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36
Origin: https://codebashing.com
Referer: https://codebashing.com/courses
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Cookie: sessionid=55fc9da99a9d425c8ec8c597fd5bec61
Content-Type: application/x-www-form-urlencoded
Content-Length: 46
Connection: close
login=alice&password=correcthorsebatterystaple
GET /courses HTTP/1.1
Host: codebashing.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36
Origin: https://codebashing.com
Referer: https://codebashing.com/dashboard
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ru;q=0.8
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Cookie:sessionid=b3cd288f3e3d499ca8e45fbae696f7b5
Connection: close
URLs are used to locate resources on the Internet. Let’s take a look at the URL structure that is used with HTTP (for other protocols, URL format may differ).
scheme://authority/path?query#fragment
In HTTP requests and responses, the following types of headers are used:
- Request
- Response
- Entity
- General
- Custom application defined The complete list of HTTP headers can be found in HTTP RFCs.
This header is used to route through the different applications hosted on the same IP address. Note that the Host header is completely under the user control (so, do not use its value for security checks).
This header is used by the server to define the user's client application and to serve the correct version of the requested web page. This header can be easily manipulated (e.g. some browser plug-in could change user-agent to an arbitrary value), so it shouldn't be used for security checks.
This header shows the address of the previous web page where the user clicked the link to the requested page. Referer header contains the full URL of the previous page, so if there is sensitive data in that URL, then it could be disclosed through this header. Referer header is completely under the user control, so do not use its value for security checks.
This group of headers defines what encoding, language, content type the client can understand.
This header sends a signal to the server expressing the client’s preference for an encrypted and authenticated response.
This header controls whether or not the network connection stays open after the current transaction finishes.
An HTTP cookie is a small piece of data that a server sends to a client. The server sends the cookie using the Set-Cookie header in the response. It looks like that:
Set-Cookie: trackingCookie=user1357272
User-agent saves a cookie from the response and sends it back in the Cookie request header like that:
Cookie: trackingCookie=user1357272
Cookies are used for the following purposes:
- Session management
HTTP is a stateless protocol meaning that two requests cannot be correlated to the same source or to each other even if they are sent from the same IP address and contain the same user-agent. In other words, without some additional information, the server is not able to understand that two requests were sent consequently by the same user.
To keep the flow of all the user's requests, session identifiers are used. Usually, a session identifier resides in a cookie and is sent with every request in the Cookie header. Thus the server can track all actions the user makes, display him the right interface, and send responses with correct data
- Personalization
Sometimes cookies are used to store user preferences and non-sensitive application data.
- Tracking
Nowadays many companies try to understand their users' behavior and track all the actions users make. Cookies can be used for this purpose as they can persist in the browser, until cleared, and can be tied to the user behavior, even if the user is not authenticated.
And now let us look at the response. Near the HTTP version, we can see the response code (200 OK in our example).
There are five groups of response status codes with the corresponding status message. Let us review these groups and look at the most popular status codes.
Successful responses
200 – OK
This status shows that the request has succeeded. Either the desired information exists on the server and is transmitted in the response body, or the desired application state change has been performed successfully.
Redirection responses
301 – Moved permanently
The status means that the desired resource resides at another location (which is usually specified in the Location header of the response).
302 – Found
The status also means that the desired page has been moved and a new location is specified in the Location header of the response. But in this case, the page has been moved temporarily.
304 – Not Modified
This code is used to instruct the browser to used cached data because it hasn’t changed since the previous request.
Client error responses
400 – Bad Request
This status means that the request syntax is invalid and the server was not able to process it.
401 – Unauthorized
This status means that the requested resource requires a client to be authenticated.
403 – Forbidden
This status means that the authenticated user does not have permissions to access the requested resource.
404 – Not Found
This code shows that the requested resource does not exist on the server.
Server error responses
500 – Internal Server Error
This code means that the request syntax is correct, but the server could not prepare a response for the request due to an exception thrown by the application code.
You should NEVER use the following headers in implementations of security mechanisms: Host Referer
The Content-Type header is not actually a security header, and content type validation cannot be treated as a standalone security mechanism. But it is definitely an important part of the defense-in-depth strategy.
By setting Content-Type in request and response headers, the programmer can manipulate the way the server will interpret the body of the corresponding HTTP request or response. If the server doesn't check the content header value, it leaves a possibility for an attacker to manipulate the application's behavior by tampering with the Content-Type header content.
In the right pane, there is an example of a JQuery vulnerability that is based on the missing Content-type header.
In versions prior to 3.0.0, JQuery automatically evaluates the response body if response Content-Type header is text/javascript for cross-domain requests.
If the datatype is not specified in $.get(), then the method doesn’t wait for a specific type of content and processes any kind of content received in response. If the content is javascript, it is automatically evaluated.
The vulnerability was mitigated by implementing content type validation: if an application does not expect javascript in the response, then it is not executed.
When the user agent (usually, a browser) is trying to guess the content type, it is called MIME sniffing. This feature can be abused by an attacker and the browser can be tricked into interpreting malicious data, for example, in an XSS attack.
In HTTP response, there is an X-Content-Type-Options header that has a single nosniff directive. It indicates that the user agent should not perform MIME sniffing and should treat the body content as the content of the type specified in the Content-Type header.
X-Content-Type-Options is also not a security header, but together with Content-Type, they make a valuable input into the defense-in-depth strategy. Don't let the user agent guess the content type, because missing content type check can lead to the execution of content that should not be executed, or to a security controls bypass.
Referer header contains the address of the webpage that sent the HTTP request. It's is set by the browser and cannot be set using Javascript.
The major security considerations about the Referer header is that even though it's set by the browser and cannot be manipulated using the Javascript, the header content must not be used for making security-related and business logic-related decisions. It can be manipulated by an attacker as any other part of the HTTP request, thus making all the security mechanisms based on the Referer header check flawed by design.
The Referer header usually contains the full URL of the page that initiated the request. If the URL contains sensitive data, then ordinary legitimate requests to analytical systems or image storages disclose that data from the URL. To prevent this, one must avoid storing sensitive data in the URL and use Referrer-Policy header, rel or referrerpolicy HTML tag attributes.
The Referrer-Policy header instructs user agents which referrer information, sent in the Referer header, should be added to the request. In other words, Referrer-Policy is an additional control that ensures that sensitive data doesn't leak from the Referer header.
HTML tag attributes enable similar behavior but apply it to a specific tag.
The Host header specifies which website or a web application hosted on the same web server (with the same IP address) should process an incoming HTTP request. It contains the domain name of the server, and (optionally) the TCP port number on which the server is listening. This header is set by the browser and cannot be modified using Javascript.
Even though Host header is set by browsers and cannot be manipulated using Javascript, its content must not be used for making security-related and business logic-related decisions. The header content (as any other part of the HTTP request) can be manipulated by an attacker, and that makes mechanisms based on the Host header check flawed by design.
In the right pane, you can see an example of a business logic-related decision that relies on the information from the Host header of the incoming request.
Bob is a hacker. While he was scanning the application for vulnerabilities, he noticed that the server puts the location information in the cookie as is. If the location value is not sanitized, then this looks like a great chance to perform the HTTP Response Splitting attack. Bob crafts the malicious payload that will trick the server into sending the page that contains a cookie-stealing script: Cyberville\r\nContent-length: 113\r\n\r\n<script>document.write("");</script> Then he puts it into the intercepted GET request instead of the legitimate payload.
HTTP Response Splitting was used to trick the server into returning the malicious payload as a legitimate webpage in the response. This is achieved by using \r\n combination of symbols to make the server interpret it as a line break and to insert the malicious page content over the legitimate one.
Cache Poisoning happened when that malicious response was saved in cache and then served to users in response to their ordinary requests.
In the right pane, there are two examples of how the \r\n combination can be used to:
insert an arbitrary custom header (e.g. to bypass some security control) insert a new Content-Length header and a response body for the XSS or defacement attack Each time you develop some new request parsing logic on your web server, make sure you filter out \r\n combination of symbols (or each of them separately) to prevent HTTP Response Splitting.
Content-Security-Policy (CSP) is a special HTTP response header that tells the browser what are the safe sources of the content for the page it is going to load.
When those safe sources are specified, it prevents the hacker from tricking the browser into loading and running malicious scripts in the user’s browser, injecting iframes with some malicious or unauthorized content, displaying fake images or basically injecting anything from a remote untrusted domain.
CSP can also be used to ensure that all the content is loaded via HTTPS, and it also prevents Clickjacking by instructing the browser that it shouldn't allow the certain page to be loaded in an iframe.
Content-Security-Policy: script-src 'strict-dynamic' 'nonce-RandomValue' 'unsafe-inline' http: https:https://codebashing.com; object-src 'none';
What this policy does:
It allows all scripts that have the RandomValue nonce specified and propagates the trust to all the scripts loaded by these scripts;
It will ignore scripts from https://codebashing.com unless they have the nonce specified;
It specifies the schemas that may be used to retrieve the scripts: http or https;
It disallows objects that can be used to execute JavaScript like , or tags.
As we've just learned, Content-Security-Policy header instructs the browser which sources of scripts (and other content) are trusted, and the browser runs only those scripts that were taken from those trusted sources and ignores all the inline scripts and HTML event attributes (unless it's instructed otherwise).
It is important to emphasize:
CSP doesn't prevent the injection of malicious scripts itself. Those scripts can be injected by some hacker. But they will not run, because CSP will instruct the browser to execute only the scripts taken from the trusted sources specified in the policy.
So CSP shouldn’t be used as the only security control to prevent XSS or injection of malicious content. It should be used as a part of the defense-in-depth strategy against XSS and other vulnerabilities.
Content-Security-Policy: script-src https://codebashing.com unsafe-inline' 'unsafe-eval'; img-src * ; default-src 'self'
What does this policy do?
It allows scripts loaded from https://codebashing.com
It allows script from inline resources
It allows usage of eval() and similar unsafe JavaScript methods
It allows images from any source
When the type of content is not specified, it falls back to the default policy that allows content loaded from the current origin.
It is important to mention that the Content Security Policy must be thoroughly tested prior to the implementation in the production environment. CSP misconfiguration can easily break the application's functionality and ruin the user experience.
A misconfigured CSP is likely to be loosened or turned off, and a loosened CSP in most cases is as insecure as a missing CSP.
CSP is constantly evolving. The current version of CSP is "level 2". "Level 3" version of it exists but it is still in a draft, nevertheless modern browsers support most of it. (CSP header can be not compatible with old browsers. Browsers that don’t support CSP just ignore the CSP header.)
This set of directives controls locations used to load different types of resources.
Please note that in order to mitigate XSS, you should define either default-src and script-src directives or object-src and script-src directives.
The default-src directive defines a default source of content for the webpage. It is used as a fallback when a specific directive is not defined. All fetch directives fall back to default-src if they are not defined.
This directive defines sources for , and tags. Note that using these tags allows for arbitrary javascript execution, so it must be included into the policy in order to prevent XSS.
This directive defines sources of JavaScript like <script>, javascript:, eval(), etc.
It should be configured carefully because misconfiguration usually leaves an opportunity to bypass CSP.
The directive allows more granular configuration using keywords. Note that these keywords turn off some security features leaving CSP bypassable.
This directive is deprecated in CSP Level 3. Usage of frame-src and worker-src is recommended instead.
The directive defines sources for web workers and nested browsing contexts loaded using <iframe> or tags.
The directive restricts usage of XMLHttpRequests, Fetch, WebSockets, EventSource and , only the URLs specified in the policy can be loaded using methods mentioned previously.
frame-src
The directive specifies valid sources for nested browsing context using <iframe> or .
font-src
The directive specifies sources of fonts.
img-src
The directive specifies sources of images.
manifest-src
The directive specifies sources of a web application manifest.
media-src
The directive specifies sources of media loaded in or
prefetch-src
The directive specifies the URL from which resources can be prefetched or pre-rendered.
style-src
The directive specifies sources of style sheets.
worker-src
The directive specifies sources of web workers.
unsafe-inline
Without this keyword, CSP will trust only scripts loaded from the specified resources. It won't permit inline scripts residing on the webpage between <script>, <style> tags, in javascript: and event handlers.
This keyword allows inline script sources and thus removes the protection against XSS that CSP provides.
If there is no possible way to avoid using inline javascript, then nonce or hash source should be used.
unsafe-eval
This keyword allows usage of functions that evaluate code presented as a string, e.g. eval(), Function(), etc.
strict-dynamic
This keyword is used with a nonce or hash source, e.g. script-src ‘strict-dynamic’ ‘nonce-RandomValue’ or script-src ‘strict-dynamic’ ‘sha-256-base64EncodedHash’.
The nonce received in the header should be a part of <script>, e.g. <script nonce=”RandomValue” src=”script URL”>, thus the browser understands that this script is trusted and can be executed.
The hash received in the header is the base64 representation of a sha256 (384 or 512) hash of the script.
default-src
The default-src directive defines a default source of content for the webpage. It is used as a fallback when a specific directive is not defined. All fetch directives fall back to default-src if they are not defined.
object-src
This directive defines sources for , and tags. Note that using these tags allows for arbitrary javascript execution, so it must be included into the policy in order to prevent XSS.
script-src
This directive defines sources of JavaScript like <script>, javascript:, eval(), etc.
It should be configured carefully because misconfiguration usually leaves an opportunity to bypass CSP.
The directive allows more granular configuration using keywords. Note that these keywords turn off some security features leaving CSP bypassable.
child-src
This directive is deprecated in CSP Level 3. Usage of frame-src and worker-src is recommended instead.
The directive defines sources for web workers and nested browsing contexts loaded using <iframe> or tags.
connect-src
The directive restricts usage of XMLHttpRequests, Fetch, WebSockets, EventSource and , only the URLs specified in the policy can be loaded using methods mentioned previously.
These directives control the properties of a document or worker environment to which a content security policy applies.
In the right pane, click the directive you want to explore, and the description will appear instantly.
base-uri
The directive restricts the URLs that can be used in element which defines the base URLs to be prepended to relative URLs used in the page.
plugin-types
The directives defines types of plug-ins used in , , tags, e.g. flash objects or java applets.
sandbox
The directive applies a sandbox attribute to the current page. It behaves like a sandbox attribute used in <iframe> allowing to restrict execution of scripts and plug-ins, block pop-ups, etc.
disown-opener
The directive instructs a browser to set window.opener object to null when the user is navigated from a CSP-protected page to a new tab or window. Check out the Reverse Tabnabbing lesson to understand what purpose this directive serves.
Note that the directive is not finalized; alternative security controls should be used.
These directives restrict URLs that are used to navigate the user from the current page using different HTML tags.
form-action
The directive specifies the URLs that can be used as targets of form submission, e.g. targetURL in
.frame-ancestors
The directive specifies sources that may open the page in <iframe>, , , and tags.
The directive partially overlaps with the X-FRAME-OPTIONS HTTP header and serves the same purpose.
Check Clickjacking lesson to learn more about X_FRAME_OPTIONS and frame-ancestors.
navigate-to
The directive restricts the URLs to which document can initiate navigation using any navigation means.
Note that the directive is a part of CSP level 3, thus it is not published yet. There also can be support issues among browsers.
To make the CSP configuration process easier, one can use a reporting functionality that is built into the CSP (it works according to the reporting API specification at https://w3c.github.io/reporting/).
Location of report collection service can be set using report-to or report-uri directives. Also, CSP has a report-only mode that should be used for testing CSP settings. The report-only mode is activated by using Content-Security-Policy-Report-Only header.
report-to
This directive specifies a reporting group that should be used to send reports. Reporting groups are set in Report-To response header. Reporting group is created according to the reporting API (https://w3c.github.io/reporting/).
report-uri
This directive specifies the URL that the user-agent should use to report CSP violation.
Note that this directive is deprecated in CSP level 3 and the usage of Report-To is recommended.
Currently, Report-To is not widely supported by browsers, thus the usage of both directives is recommended for the backward compatibility. If Report-To is presented and supported by the browser, then report-uri directive is ignored.
block-all-mixed-content
This directive prevents loading of any page components via HTTP if the page is loaded via HTTPS.
require-sri-for
This directive makes subresource integrity (SRI) usage mandatory for scripts or/and style sheets. For example, SRI allows to specify a loaded script hash and to check that script hasn’t changed.
upgrade-insecure-requests
This directive instructs the user-agent to upgrade non-navigational requests from HTTP to HTTPS.
So, how to configure the effective Content Security Policy? We have some tips for you:
-
CSP should restrict at least sources of scripts and objects.
-
Use a whitelist of specific scripts containing the nonce specified in the policy or compare the script hash with the hash specified in the policy.
-
Avoid using unsafe-inline and unsafe-eval or at least use them with a nonce or a hash.
-
Test your policy before going to production.
-
Use CSP only in the report-only mode for a pilot run on production.
Web Cache Deception is another technique for attacking caches. It's different from the HTTP Cache Poisoning attack because no tainted data is saved in the cache and then served to users (which is what Cache Poisoning implies). During the Web Cache Deception attack, a malicious user gains unauthorized access to sensitive data of another user by exploiting ordinary cache behavior.
The following conditions should be met for the attack to succeed:
-
The web server returns the contents of the "root" page (https://codebashing.com/home/) when a nonexistent static file (like https://codebashing.com/home/somecss.css) is requested. (In other words, the URL is rewritten from route /home/somecss.css to /home/.)
-
Web cache disregards HTTP headers that define caching behavior and relies on file extensions (in our example - a CSS file).
-
A victim is authenticated while accessing a malicious URL.
The vulnerable application pane loads the online shopping application LotsOfGoods.me. It aggregates data from multiple off-line shops and presents it on a single platform. The user can buy goods from all those sellers right from the application.
So, let us quickly recap what had happened during the attack.
-
Bob lured the authenticated user (Alice) on a page with a nonexistent static resource (a CSS file in our case: https://lotsofgoods.me/myaccount/profile/revieworder.css).
-
The web server returned the contents of https://lotsofgoods.me/myaccount/profile/ page ignoring the filename and its extension.
-
Web cache disregarded HTTP headers that define caching behavior and cached the returned page (with all sensitive data of the logged on user) as a static file, based on its extension.
-
As a result, a subsequent request of the attacker to the https://lotsofgoods.me/myaccount/profile/revieworder.css showed the response for https://lotsofgoods.me/myaccount/profile/ with user's sensitive data.
To prevent Web Cache Deception, make sure the following conditions are met:
-
Only static content is cached, and it is separated from the rest of the content.
-
In case a non-existent page (or file) is requested, 404 page is returned or a redirect to the home page is performed using the HTTP 302 response code.
-
Caching directives from HTTP headers are taken into consideration and not ignored.
Caching is a mechanism designed to decrease the server load and speed up the loading of web pages. A cache saves copies of server responses and serves them to users upon their repeating requests.
The cache can operate locally in the user’s browser, or there are also intermediate caches: caching proxies, load balancers, CDNs, web servers. Our lesson is devoted specifically to intermediate caches.
In case of a browser cache, when a user requests some data, the browser first checks if the requested data is cached and not expired, then the cache serves the user the cached version of data. In case of an intermediate cache, the same logic is applied: first, the cache checks if the requested data is saved and not expired, and then serves it to users. It also allows serving data when the server is down.
Usually static content like images, stylesheets, or scripts is cached.
Also, every cache provider has its own caching preferences and capabilities. To enable them, custom headers (that are specific to a certain cache provider) can be used. Those custom headers start with "X-" (like "X-Some-Header").
These headers are not a part of the HTTP standard and thus can be treated differently by different software.
Cache-Control
This general header defines the behavior of caching mechanisms through directives. Directives allow disabling of caching or fine-tuning of the caching behavior (e.g. specifying what kind of caching providers can cache the response, defining cache storage period, managing usage of the stale cache).
Pragma
This header with the no-cache directive is equal to the Cache-Control: no-cache header. It is used for the backward compatibility with HTTP/1.0 caching mechanisms. The header is not supported by some user agents, thus using Cache-Control header as a reliable caching mechanism is more preferable.
Age
This header specifies the number of seconds a response has been stored in an intermediate cache.
Expires
This header sets the date and time when the ached response becomes expired.
ETag and Precondition headers (If-*)
These headers are used to validate the freshness of cached data. ETag header value stores a version of the resource and If-* headers define additional conditions of ETag verification.
When a cache receives a request for some resource, it needs to check if it has already saved a copy of this resource and can return it to the user immediately, or it needs to forward the request to the application server.
Identifying whether the user requests the same resource that is already stored in the cache can be tricky. Caches solve this problem by using the concept of cache keys. Some component of the HTTP request can be set as keys (in cache settings).
When a request comes to the cache server, it checks first which headers of that request are keyed. Then it takes all those keyed headers with their values together and calculates the hash. After that this hash is used to search through the cached responses (responses are stored together with hashes of keyed headers of respective requests).
In the right pane, you can see the animated diagram of the cache using keyed headers to calculate the hash for the incoming request and retrieve the correct cached response to the user. Note that it is a simplified description, and it might be not valid for all existing caching software.
The general idea of the Cache Poisoning attack is to make the cache save the resource that contains some malicious data and then serve it to users that request this resource. This attack allows performing a further XSS attack, defacing a page, redirecting a user to an arbitrary domain and bypassing access control mechanisms.
In this lesson, we will talk about basic Cache Poisoning using the unkeyed HTTP request components. During this attack, the hacker will send some malicious content in the unkeyed request header, hoping that it will be used in the response, cached and then served to other users of the application requesting the same resource.
The vulnerable application pane loads the online shopping application LotsOfGoods.me. It uses X-Script-Source custom header to pass a domain name to the server, where this name will be used to generate the URL to run the counter script on the page. This header is unkeyed, so the cache doesn't use it for identification purposes.
Bob is a hacker looking for possibilities for an attack on a yet-another shopping application. He is using his Burp Suite Param Miner plug-in against the LotsOfGoods.me application to find out which components (headers, cookies) of the HTTP request are unkeyed. In the scanning results, he sees that there is an unkeyed parameter in the request: X-Script-Source header.
The name of this header implies that it contains some information that allows detecting the path to the folder that contains scripts, and this path is probably used somewhere in the code of the page.
Bob analyzes the code of the web page and finds out that the domain name passed in the X-Script-Source header is used to create an URL of the counter script that is used on the page. Now Bob needs to test how far he can go with the exploitation of that unkeyed request component.
On his malicious server, he creates the folder structure that is the same as in the legitimate script link and puts there his malicious script that steals user cookies.
The only thing he needs to do next is to put the name of his malicious server into the X-Script-Source header of the intercepted request.
To poison cache with his malicious request, Bob needs to make sure that he sends it to the application right after the current cached response expires. To define the correct time, he uses the values of the Age header and max-age directive of the Cache-Control header of the server response.
Now each user that will request the LotsOfGoods.me homepage in the next 2400 seconds will receive Bob's malicious response from the cache server. The script will be executed in their browsers, and their cookies will be stolen.
Manipulating unkeyed HTTP request component, an attacker can do a lot of harm if these components influence the page content. To prevent cache poisoning, you should do the following:
-
Cache only static data.
-
If you are using some third-party service for caching, check which security controls against cache poisoning it provides.
-
Do not trust any data from header directives of the HTTP requests. Always consider it tainted by default.
-
When you cache a page, make sure that all the headers of the HTTP request that influence the page content - are keyed. And vice versa, if some header is unkeyed, don't use it in any business logic that implies influencing the page content.
-
Check if your caching mechanism or framework is configurable to prevent cache poisoning.
ame-Origin Policy (SOP) is a major security concept that is built-in in all contemporary browsers. Its main goal is to prevent access attempts of dynamic web page elements (like scripts) to data on resources of a different origin.
In the security context, SOP prevents malicious web sites from retrieving confidential data from restricted locations on behalf of users and without their acknowledgment.
User agents that are compliant with SOP, restrict requests issued from one origin to another origin. For example, popular JS libraries such as JQuery, XmlHttpRequests and Fetch API follow the Same-Origin Policy.
In the right pane, you can see the animated diagram of how SOP works when enabled in the browser.
To identify an origin, SOP uses the scheme, the hostname (domain name with or without subdomains, or IP address), and the port number. If those three parameters of two resources match, then these resources have the same origin.
Let us consider an example where there is no Same-Origin Policy at all.
Bob creates a website coolnews.me with funny cat pictures and adds there a basic javascript that makes a request to the website of a popular social network friendslist.me, reads the contents of a page with personal details exactly as the authenticated victim would, both body and headers, and sends them to Bob's server.
If he shares a link to his website on his social network page, then everyone who follows that link will involuntarily share their personal details with Bob.
With Same-Origin Policy enabled, the browser allows only some basic HTTP requests (e.g. GET and POST requests without any custom HTTP headers) from the resource of one origin to the resource of another origin, and will never allow a script from the Coolnews.me to read the response from the Friendslist.me (unless CORS is also enabled).
In the case with Bob's malicious page, the browser will first send a preflight request to the Friendslist.me website to ensure that the request is allowed, and, since Friendslist.me knows nothing about Coolnews.me and doesn't trust it, it disallows the access. The browser will then prevent the malicious request from ever being sent.
Cross-Origin Resource Sharing (CORS) is a way to deliberately disable SOP. We may need it for implementation of some business logic that requires sending requests to another origin, like performing interactions with cloud services, creating a single-page design, using sharing or liking functionality, etc.
The main idea of CORS is to negotiate with the server on the conditions of the cross-origin request. As a result, either a resource from one origin will be allowed to send an HTTP request to the resource from another origin and read the contents of the response, or the request will be aborted due to the disabled cross-origin resource sharing.
In the right pane, you can see that the cross-origin request to the server that provides stock market quotes for the news website was aborted.
For the requests that do not meet the requirements below, negotiation on the conditions of the cross-origin request is performed using a preflight request. Preflight requests are triggered when the following conditions are NOT met.
-
An initial cross-origin request uses GET, HEAD or POST methods. For POST method, only application/x-www-form-urlencoded, multipart/form-data, or text/plain content types are allowed.
-
The cross-origin request doesn't contain custom HTTP headers and includes only the headers explicitly allowed by the CORS policy.
-
No event listeners are registered on an XMLHttpRequestUpload object that is used in the cross-origin request.
-
No ReadableStream objects are used in the cross-origin request.
In other words, a cross-origin request that meets the conditions above doesn't trigger the preflight request.
Instead of the preflight request, negotiation on the conditions is performed using the Origin header in the request, and the Access-Control-Allow-Origin header in the response. If the Access-Control-Allow-Origin header contains the specified origin or an asterisk, the content of the response becomes accessible to the code that performed the request.
When the preflight request is triggered, the initial request is postponed until the server confirms the properties of the request to be sent. The preflight request is an HTTP OPTIONS request that contains Origin header and may include CORS-specific headers.
CORS mechanism uses several HTTP headers to agree on cross-origin communication parameters.
Origin
This header indicates the origin that initiates a request
Access-Control-Request-Method
This header indicates the HTTP request methods that will be used in the further cross-origin request
Access-Control-Request-Headers
The header indicates the headers that will be used in the further cross-origin request
Access-Control-Allow-Origin
The header specifies the origin that may access the requested resource. If the header value is * then any origin may access the resource.
Access-Control-Max-Age
The header specifies how long information from Access-Control-Allow-Methods and Access-Control-Allow-Headers should be cached.
Access-Control-Allow-Methods
The header specifies the method or methods that may be used in the original cross-origin requests to the resource.
Access-Control-Expose-Headers
The header specifies the list of headers that browsers are allowed to access in the original cross-origin header when a requester processes the response.
Access-Control-Allow-Credentials
The header indicates that the server will accept the original request if it contains credentials. In this case, credentials may be one of the following: HTTP cookies, TLS certificates, and HTTP authentication headers.
In order to use credentials, the requesting origin should declare that their usage explicitly e.g. set XHRObject.withCredentials = true or set a fetch request credentials mode to "include".
The header usually contains "true" value or is not present.
Access-Control-Allow-Headers
The header specifies the headers that may be used in the original cross-origin requests to the resource. Simple response headers are available by default, but custom headers will require whitelisting.
Apex runs in system context - the current user's permissions, field-level security, and sharing rules are not taken into account during code execution. Web services can be restricted by permissions, but execute in system context once they are initiated.
Enforcing sharing rules by using the with sharing keyword doesn’t enforce the user's permissions and field-level security. Apex code always has access to all fields and objects in an organization, ensuring that code won’t fail to run because of hidden fields or objects for a user.
Enforcing the current user's sharing rules can impact: • SOQL and SOSL queries. A query may return fewer rows than it would operating in system context. • DML operations. An operation may fail because the current user doesn't have the correct permissions. For example, if the user specifies a foreign key value that exists in the organization, but which the current user does not have access to.
Apex doesn't enforce object-level and field-level permissions by default, you can enforce these permissions in your SOQL queries by using WITH SECURITY_ENFORCED
.
Enforce object-level and field-level permissions in your code by explicitly calling the sObject describe result methods (of Schema.DescribeSObjectResult
) and the field describe result methods (of Schema.DescribeFieldResult
) that check the current user's access permission levels. In this way, you can verify if the current user has the necessary permissions, and only if he or she has sufficient permissions, you can then perform a specific DML operation or a query.
For example, you can call the isAccessible
, isCreateable
, or isUpdateable
methods of Schema.DescribeSObjectResult
to verify whether the current user has read, create, or update access to an sObject, respectively.
Schema.DescribeFieldResult
exposes access control methods to call to check the current user's read, create, or update access for a field. In addition, you can call isDleteable
method provided by Schema.DescribeSObjectResult
to check if the current user has permission to delete a specific sObject.
To check the field-level update permission of the contact's email field before updating it:
if (Schema.SObjectType.Contact.fields.Email.isUpdateable()) {
// Update email address
}
To check the field level create permission of the contact's email address field before creating a new contact:
if (Schema.SObjectType.Contact.fields.Email.isCreateable()) {
// Create new contact
}
To check the field-level read permission of the contact's email field before querying for this field:
if (Schema.SObjectType.Contact.fields.Email.isAccessible()) {
Contact c = [SELECT Email FROM Contact WHERE Id =:Id];
}
To check the object-level permission for the contact before deleting the contact
if (Schema.SObjectType.Contact.isDeletable()) {
// Delete contact
}
If you call the SObject describe result
and field describe result
access control methods, the verification of object and field-level permissions is performed in addition to the sharing rules that are in effect.
- Sometimes, the access level granted by a sharing rule could conflict with an object-level or field-level permission.
Specify which users can execute methods in a top-level class based on their user profile or permission sets. You can only set security on Apex classes and not on permission sets.
Sharing is the act of granting a user or group of users permission to perform a set of actions on a record or set of records. Sharing access can be granted using the Salesforce user interface and Lightning Platform, or programmatically using Apex.
Sharing enables record-level access control for all custom objects, as well as many standard objects (such as Account, Contact, Opportunity and Case). Administrators first set an object’s organization-wide default sharing access level, and then grant additional access based on record ownership, the role hierarchy, sharing rules, and manual sharing. Developers can then use Apex managed sharing to grant additional access programmatically with Apex.