Koba

Koba 是一个 Kitura 中间件,用于设置 HTTP 安全标头,以帮助缓解漏洞并防御攻击者。 它包含严格的默认配置和一个策略构建器,用于设计和覆盖安全标头值。

安全标头

安全标头是 HTTP 响应标头,设置后可以通过启用浏览器安全策略来增强 Web 应用程序的安全性。

您可以在 securityheaders.comMozilla Observatory 评估 HTTP 响应标头的安全性。

Koba 使用的建议以及有关安全标头的更多信息可以在 OWASP 安全标头项目Mozilla Web Security 中找到。

Cache-control(缓存控制)

防止缓存 HTTPS 响应
默认值: no-cache, no-store, must-revalidate, max-age=0

Content-Security-Policy (CSP)(内容安全策略)

防止跨站注入
默认值: script-src 'self'; object-src 'self' (默认情况下未包含)

Expect-CT(预期证书透明度)

强制执行证书透明度 默认值: max-age=0 (默认情况下未包含)

Feature-Policy(功能策略)

禁用浏览器功能和 API
默认值: accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; sync-xhr 'none'; usb 'none'; vr 'none' (默认情况下未包含)

Strict-Transport-Security (HSTS)(严格传输安全)

确保应用程序通信通过 HTTPS 发送
默认值: max-age=86400; includeSubDomains

Referrer-Policy(引用策略)

如果同源则启用完整引用,跨域则删除路径,并在不受支持的浏览器中禁用引用
默认值: no-referrer, strict-origin-when-cross-origin

X-Content-Type-Options (XCTO)(X-内容类型选项)

防止 MIME 嗅探
默认值: nosniff

X-Frame-Options (XFO)(X-框架选项)

禁用来自不同源的框架(点击劫持防御)
默认值: SAMEORIGIN

X-XSS-Protection (XXP)(X-XSS 保护)

启用浏览器跨站脚本过滤器
默认值: 1; mode=block

重要信息

用法

将 Koba 添加到您的 Package.swift

添加到 dependencies

.package(url: "https://github.com/cak/koba", from: "0.2.0"),

添加到 target dependencies

.target(name: "name", dependencies: ["Koba"]),

导入包

import Koba

默认配置

import Kitura
import Koba

let koba = Koba()

let router = Router()
router.all(middleware: koba)

默认 HTTP 响应标头

X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: no-referrer, strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN
Cache-control: no-cache, no-store, must-revalidate, max-age=0
Strict-Transport-Security: max-age=86400; includeSubDomains

选项

您可以通过传递带有 Header().default() 的对象来切换具有默认值的标头的设置,或者使用 nil 来删除标头。 您可以通过为自定义标头值传递 Header().set("custom") 或使用以下选项的策略构建器来覆盖默认值

例子

import Kitura
import Koba

let config = KobaConfig(
            cacheControl: CacheControl()
                .noStore()
                .mustRevalidate()
                .proxyRevalidate(),
            csp: CSP()
                .defaultSrc(Koba.Source.none)
                .blockAllMixedContent()
                .connectSrc(Koba.Source.sameOrigin, "api.swiftserver.dev"),
            expectCT: ExpectCT()
	            .maxAge(Koba.Time.fiveMinutes)
	            .enforce(),
            featurePolicy: FeaturePolicy()
                .geolocation(Koba.Source.sameOrigin, "swiftserver.dev")
                .vibrate(Koba.Source.none),
            hsts: HSTS()
                .includeSubdomains()
                .preload()
                .maxAge(Koba.Time.oneWeek),
            referrerPolicy: ReferrerPolicy()
                .noReferrer(),
            xcto: nil,
            xfo: XFO()
                .deny(),
            xxp: XXP()
                .enabledBlock()
        )

let koba = Koba(config: config)
router.all(middleware: koba)
Referrer-Policy: no-referrer
Strict-Transport-Security: includeSubDomains; preload; max-age=604800
Cache-control: no-store, must-revalidate, proxy-revalidate
Expect-CT: max-age=300; enforce
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'none'; block-all-mixed-content; connect-src 'self' api.swiftserver.dev
Feature-Policy: geolocation 'self' swiftserver.dev; vibrate 'none'
X-Frame-Options: DENY

策略构建器

助手函数

Koba.Source

Koba.Time

例子

let config = KobaConfig(
    csp: CSP().defaultSrc(Koba.Source.sameOrigin),
    hsts: HSTS().maxAge(Koba.Time.oneDay)
)

let koba = Koba(config: config)
Content-Security-Policy: default-src 'self'
Strict-Transport-Security: max-age=86400

CacheControl()

指令: private(), public(), immutable(), maxAge(seconds), maxStale(seconds), minFresh(seconds), mustRevalidate(), noCache(), noStore(), noTransform(), onlyIfCached(), proxyRevalidate(), sMaxage(seconds), staleIfError(seconds), staleWhileRevalidate(seconds)

例子

let policy = CacheControl()
    .noStore()
    .mustRevalidate()
    .proxyRevalidate()

// no-store, must-revalidate, proxy-revalidate

资源: Cache-Control | MDN

CSP()

指令: baseUri(sources), blockAllMixedContent(), connectSrc(sources), defaultSrc(sources), fontSrc(sources), formAction(sources), frameAncestors(sources), frameSrc(sources), imgSrc(sources), manifestSrc(sources), mediaSrc(sources), objectSrc(sources), pluginTypes(types), reportTo(ReportTo), reportUri(uri), requireSriFor(values), sandbox(values), scriptSrc(sources), styleSrc(sources), upgradeInsecureRequests(), workerSrc(sources)

您可以在 CSP Evaluator 检查 CSP 策略的有效性。

例子

let policy = CSP()
    .defaultSrc(Koba.Source.none)
    .baseUri(Koba.Source.sameOrigin)
    .blockAllMixedContent()
    .connectSrc(Koba.Source.sameOrigin, "api.swiftserver.dev")
    .frameSrc(Koba.Source.none)
    .imgSrc(Koba.Source.sameOrigin, "static.swiftserver.dev");

// default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' api.swiftserver.dev; frame-src 'none'; img-src 'self' static.swiftserver.dev

报告

Content-Security-Policy-Report-Only

使用 reportOnly() 会将标头更改为 Content-Security-Policy-Report-Only

例子

let policy = CSP()
    .defaultSrc(Koba.Source.none)
    .baseUri(Koba.Source.sameOrigin)
    .reportOnly()
    
let config = KobaConfig(csp: policy)
let koba = Koba(config: config)
router.all(middleware: koba)
Cache-control: no-cache, no-store, must-revalidate, max-age=0
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy-Report-Only: default-src 'none'; base-uri 'self'
Referrer-Policy: no-referrer, strict-origin-when-cross-origin
Strict-Transport-Security: max-age=63072000; includeSubdomains
X-Frame-Options: SAMEORIGIN

report-to

let reportToEndpoint = CSP.ReportToEndpoint(url: "https://swiftserver.dev/reports")

let reportTo = CSP.ReportTo(group: "CSP-Endpoint",
                            maxAge: Koba.Time.oneWeek,
                            endpoints: [reportToEndpoint],
                            includeSubdomains: true)

let policy = CSP()
    .defaultSrc(Koba.Source.none)
    .baseUri(Koba.Source.sameOrigin)
    .reportTo(reportTo)

// default-src 'none'; base-uri 'self'; report-to {"group":"CSP-Endpoint","endpoints":[{"url":"https:\/\/swiftserver.dev\/reports"}],"include_subdomains":true,"max_age":604800}

report-uri

let policy = CSP()
    .defaultSrc(Koba.Source.none)
    .baseUri(Koba.Source.sameOrigin)
    .reportUri("https://swiftserver.dev/reports")

// default-src 'none'; base-uri 'self'; report-uri https://swiftserver.dev/reports

资源: CSP Cheat Sheet | Scott Helme , Content-Security-Policy | MDN , Content Security Policy Cheat Sheet | OWASP , Content Security Policy CSP Reference & Examples, 报告: The Reporting API | Google Developers, CSP: report-uri | MDN, report-to - HTTP | MDN

ExpectCT()

指令: maxAge(seconds), enforce(), reportUri(uri)

例子

let policy = ExpectCT()
    .maxAge(Koba.Time.oneDay)
    .enforce()
    .reportUri("https://swiftserver.dev")

// max-age=86400; enforce; report-uri="https://swiftserver.dev"

资源: Expect-CT | MDN

FeaturePolicy()

指令: accelerometer(allowlist), ambientLightSensor(allowlist), autoplay(allowlist), camera(allowlist), documentDomain(allowlist), encryptedMedia(allowlist), fullscreen(allowlist), geolocation(allowlist), gyroscope(allowlist), magnetometer(allowlist), microphone(allowlist), midi(allowlist), payment(allowlist), pictureInPicture(allowlist), speaker(allowlist), syncXhr(allowlist), usb(allowlist), vibrate(allowlist), vr(allowlist)

例子

let policy = FeaturePolicy()
    .geolocation(Koba.Source.sameOrigin, "swiftserver.dev")
    .vibrate(Koba.Source.none)

// geolocation 'self' swiftserver.dev; vibrate 'none'

资源: A new security header: Feature Policy | Scott Helme , Feature-Policy | MDN , Introduction to Feature Policy | Google Developers

HSTS()

指令: includeSubdomains(), maxAge(seconds), preload()

例子

let policy = HSTS()
		.maxAge(Koba.Time.oneMonth)
    .includeSubdomains()
    .preload()

// max-age=2592000; includeSubDomains; preload

资源: Strict-Transport-Security | MDN , HTTP Strict Transport Security Cheat Sheet | OWASP

ReferrerPolicy()

指令:, noReferrer(), noReferrerWhenDowngrade(), origin(), originWhenCrossOrigin(), sameOrigin(), strictOrigin(), strictOriginWhenCrossOrigin(), unsafeUrl()

资源: A new security header: Referrer Policy | Scott Helme , Referrer-Policy | MDN

XCTO()

例子

let policy = XCTO().default()

// nosniff

资源: X-Content-Type-Options - HTTP | MDN

XFO()

指令: allowFrom(), deny(), sameorigin()

例子

let policy = XFO().deny()

// DENY

资源: X-Frame-Options | MDN

XXP()

指令: disabled(), enabled(), enabledBlock(), enabledReport(uri)

例子

let policy = XXP().enabledBlock()

// 1 mode=block

资源: X-XSS-Protection | MDN

贡献

发送拉取请求,创建 issue 或在 Kitura Slack 上与我 (@cak) 讨论。

其他

Kob'a (ko'-bah) 是希伯来语头盔的意思,是对 Helmet.js 的致敬。

正在寻找 Vapor 的安全标头? 请查看 Vapor Security Headers

资源