Background
Clickjacking, also known as a "UI redress attack", is when an attacker uses multiple transparent or opaque layers to trick a user into clicking on a button or link on another page when they were intending to click on the top level page. Thus, the attacker is "hijacking" clicks meant for their page and routing them to another page, most likely owned by another application, domain, or both. Using a similar technique, keystrokes can also be hijacked. With a carefully crafted combination of stylesheets, iframes, and text boxes, a user can be led to believe they are typing in the password to their email or bank account, but are instead typing into an invisible frame controlled by the attacker. [OWASP-CJ]
edX examples
- Imagine a legitimate-looking web site with a button that says "click here for more information". However, there's a hidden iframe loaded with the edX account settings page that is lined up exactly so that the "edX Reset Your Password" button is directly on top of the "more information" button. When a victim, who is logged into their edX account in the browser, clicks on the supposed "more information" button, they will actually click on the invisible "edX Reset Your Password" button.
Protection
Summary: Content Security Policy has more fine-grained control and better rollout-strategy. But CSP Level 2, which includes the frame-ancestors directive, is not fully adopted yet. So use X-Frame-Options for now.
The best way to protect against Clickjacking is to have the browser prevent iFraming across domains. Specifically, in the edX case, we want to prevent non-edX web pages from iFraming edX content. We do this by providing iFraming rules in our web responses that are then enforced by web browsers. There are 2 HTTP response headers that govern this: (1) X-Frame-Options and (2) frame-ancestors directive in Content-Security-Policy.
- The current OWASP recommendation is to use the X-Frame-Options header since it is supported by all major browsers. The Content-Security-Policy frame-ancestors directive was introduced only in Level 2 of the policy and isn't yet widely adopted in all browsers (only in Chrome and Firefox). [CSP]
Roll-out Strategy
Summary: Test with CSP, then deploy with X-Frame-Options.
Content Security Policy (CSP) has a great roll-out model as it allows us to first deploy new policies with reporting only capabilities (and no prevention). This allows us to find if there are any legitimate exceptions to the policy that should be excluding before actually enabling and enforcing the policy in production.
Once we have tested our policy on production using CSP, we can then implement the policy using the X-Frame-Options header response, per OWASP recommendation.
Implementation
Summary: There is django Native support for using the X-Frame-Options header, but not for CSP yet.
Middleware: django has a built-in middleware (XFrameOptionsMiddleware) for automatically adding the X-Frame-Options header to all HTTP responses from the web server.
Default setting: The default value is set in the X_FRAME_OPTIONS django setting and can have the following values:
- SAMEORIGIN
- DENY
View Decorators: The default value can be overridden using the following xframe-options decorators:
- xframe_options_deny
- xframe_options_sameorigin
- xframe_options_exempt
CSP: See Implementation section of Content Security Policy.
References
- [OWASP-CJ] OWASP page on Clickjacking
- [OWASP-CJ-CS] OWASP Cheat Sheet on Clickjacking Defense
- [CSP] Content Security Policy Reference Guide
- [django-CJ] django Clickjacking Protection