Skip to content

Commit

Permalink
Merge pull request #1 from brokenhandsio/ReferrerPolicy
Browse files Browse the repository at this point in the history
Referrer policy
  • Loading branch information
0xTim authored Feb 23, 2017
2 parents 0d53281 + a752d31 commit 0daa77a
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 2 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Easily add headers to all your responses for improving the security of your site
* X-Content-Type-Options
* Strict-Transport-Security (HSTS)
* Server
* Referrer Policy

These headers will *help* prevent cross-site scripting attacks, SSL downgrade attacks, content injection attacks, click-jacking etc. They will not help for any attacks directly against your server, but they will help your users and help secure sensitive information (CSRF tokens). Please note that this library does not guarantee anything and nothing is ever completely secure.

Expand Down Expand Up @@ -193,6 +194,24 @@ let serverConfig = ServerConfiguration(value: "brokenhands.io")
let securityHeaders = SecurityHeaders(serverConfiguration: serverConfig)
```

## Referrer Policy

The Referrer Policy is the latest header to have been introduced (the spec can be found [here](https://www.w3.org/TR/referrer-policy/)). It basically defines when the `Referrer` header can be sent with a request. You may want to not send the header when going from HTTPS to HTTP for example.

The different options are:

* ""
* "no-referrer"
* "no-referrer-when-downgrade"
* "same-origin"
* "origin"
* "strict-origin"
* "origin-when-cross-origin"
* "strict-origin-when-cross-origin"
* "unsafe-url"

I won't go into details about each one, I will point you in the direction of a far better explanation [by Scott Helme](https://scotthelme.co.uk/a-new-security-header-referrer-policy/).

## Public-Key-Pins

Coming soon
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import HTTP

public struct ReferrerPolicyConfiguration: SecurityHeaderConfiguration {

public enum Options: String {
case empty = ""
case noReferrer = "no-referrer"
case noReferrerWhenDowngrade = "no-referrer-when-downgrade"
case sameOrigin = "same-origin"
case origin = "origin"
case strictOrigin = "strict-origin"
case originWhenCrossOrigin = "origin-when-cross-origin"
case strictOriginWhenCrossOrigin = "strict-origin-when-cross-origin"
case unsafeUrl = "unsafe-url"
}

private let option: Options

public init(_ option: Options) {
self.option = option
}

func setHeader(on response: Response) {
response.headers[HeaderKey.referrerPolicy] = option.rawValue
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@ public extension HeaderKey {
static public var contentSecurityPolicyReportOnly: HeaderKey {
return HeaderKey("Content-Security-Policy-Report-Only")
}

static public var referrerPolicy: HeaderKey {
return HeaderKey("Referrer-Policy")
}
}
7 changes: 6 additions & 1 deletion Sources/VaporSecurityHeaders/VaporSecurityHeaders.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public struct SecurityHeaders: Middleware {
xssProtectionConfiguration: XssProtectionConfiguration = XssProtectionConfiguration(option: .block),
hstsConfiguration: StrictTransportSecurityConfiguration? = nil,
serverConfiguration: ServerConfiguration? = nil,
contentSecurityPolicyReportOnlyConfiguration: ContentSecurityPolicyReportOnlyConfiguration? = nil) {
contentSecurityPolicyReportOnlyConfiguration: ContentSecurityPolicyReportOnlyConfiguration? = nil,
referrerPolicyConfiguration: ReferrerPolicyConfiguration? = nil) {
configurations = [contentTypeConfiguration, contentSecurityPolicyConfiguration, frameOptionsConfiguration, xssProtectionConfiguration]

if let hstsConfiguration = hstsConfiguration {
Expand All @@ -33,6 +34,10 @@ public struct SecurityHeaders: Middleware {
if let contentSecurityPolicyReportOnlyConfiguration = contentSecurityPolicyReportOnlyConfiguration {
configurations.append(contentSecurityPolicyReportOnlyConfiguration)
}

if let referrerPolicyConfiguration = referrerPolicyConfiguration {
configurations.append(referrerPolicyConfiguration)
}
}

public func respond(to request: Request, chainingTo next: Responder) throws -> Response {
Expand Down
92 changes: 91 additions & 1 deletion Tests/VaporSecurityHeadersTests/HeaderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,16 @@ class HeaderTests: XCTestCase {
("testHeadersWithHSTSwithSubdomainAndPreloadFalse", testHeadersWithHSTSwithSubdomainAndPreloadFalse),
("testHeadersWithServerValue", testHeadersWithServerValue),
("testHeadersWithCSP", testHeadersWithCSP),
("testHeadersWithReportOnlyCSP", testHeadersWithReportOnlyCSP)
("testHeadersWithReportOnlyCSP", testHeadersWithReportOnlyCSP),
("testHeadersWithReferrerPolicyEmpty", testHeadersWithReferrerPolicyEmpty),
("testHeadersWithReferrerPolicyNoReferrer", testHeadersWithReferrerPolicyNoReferrer),
("testHeadersWithReferrerPolicyNoReferrerWhenDowngrade", testHeadersWithReferrerPolicyNoReferrerWhenDowngrade),
("testHeadersWithReferrerPolicySameOrigin", testHeadersWithReferrerPolicySameOrigin),
("testHeadersWithReferrerPolicyOrigin", testHeadersWithReferrerPolicyOrigin),
("testHeadersWithReferrerPolicyStrictOrigin", testHeadersWithReferrerPolicyStrictOrigin),
("testHeadersWithReferrerPolicyOriginWhenCrossOrigin", testHeadersWithReferrerPolicyOriginWhenCrossOrigin),
("testHeadersWithReferrerPolicyStrictOriginWhenCrossOrigin", testHeadersWithReferrerPolicyStrictOriginWhenCrossOrigin),
("testHeadersWithReferrerPolicyUnsafeUrl", testHeadersWithReferrerPolicyUnsafeUrl),
]

private var request: Request!
Expand Down Expand Up @@ -266,6 +275,87 @@ class HeaderTests: XCTestCase {
XCTAssertEqual(csp, response.headers[HeaderKey.contentSecurityPolicyReportOnly])
}

func testHeadersWithReferrerPolicyEmpty() throws {
let expected = ""
let referrerConfig = ReferrerPolicyConfiguration(.empty)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

func testHeadersWithReferrerPolicyNoReferrer() throws {
let expected = "no-referrer"
let referrerConfig = ReferrerPolicyConfiguration(.noReferrer)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

func testHeadersWithReferrerPolicyNoReferrerWhenDowngrade() throws {
let expected = "no-referrer-when-downgrade"
let referrerConfig = ReferrerPolicyConfiguration(.noReferrerWhenDowngrade)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

func testHeadersWithReferrerPolicySameOrigin() throws {
let expected = "same-origin"
let referrerConfig = ReferrerPolicyConfiguration(.sameOrigin)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

func testHeadersWithReferrerPolicyOrigin() throws {
let expected = "origin"
let referrerConfig = ReferrerPolicyConfiguration(.origin)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

func testHeadersWithReferrerPolicyStrictOrigin() throws {
let expected = "strict-origin"
let referrerConfig = ReferrerPolicyConfiguration(.strictOrigin)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

func testHeadersWithReferrerPolicyOriginWhenCrossOrigin() throws {
let expected = "origin-when-cross-origin"
let referrerConfig = ReferrerPolicyConfiguration(.originWhenCrossOrigin)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

func testHeadersWithReferrerPolicyStrictOriginWhenCrossOrigin() throws {
let expected = "strict-origin-when-cross-origin"
let referrerConfig = ReferrerPolicyConfiguration(.strictOriginWhenCrossOrigin)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

func testHeadersWithReferrerPolicyUnsafeUrl() throws {
let expected = "unsafe-url"
let referrerConfig = ReferrerPolicyConfiguration(.unsafeUrl)
let middleware = SecurityHeaders(referrerPolicyConfiguration: referrerConfig)
let drop = try makeTestDroplet(middlewareToAdd: middleware)
let response = try drop.respond(to: request)
XCTAssertEqual(expected, response.headers[HeaderKey.referrerPolicy])
}

private func makeTestDroplet(middlewareToAdd: Middleware) throws -> Droplet {
let drop = Droplet(arguments: ["dummy/path/", "prepare"])
drop.middleware.append(middlewareToAdd)
Expand Down

0 comments on commit 0daa77a

Please sign in to comment.