HTTP CSP

本文介绍了 Content Security Policy (CSP),包括其体现的限制资源获取、报告资源获取越权功能,以及限制方式。通过实验展示了如何限制 inline js 代码执行、外部链接加载的 js 文件域名、form 表单提交方向等,还说明了 CSP 出现异常时向服务器汇报的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Content Security Policy (CSP)

https://developer.mozilla.org/zh-CN/docs/Web/Security/CSP

它体现在:

 - 限制资源获取

 - 报告资源获取越权

限制方式

 - default-src 限制全局

 - 制定资源类型(资源类型如,connect-src, img-src, manifest-src, img-src, style-src, media-src, font-src, script-src, frame-src, ...)

下面我们来实验一下。

先是server.js 如下

const http = require('http')
const fs = require('fs')
const zlib = require('zlib')

http.createServer(function (request, response) {
    console.log('request come', request.url)

    const html = fs.readFileSync('test.html')
    response.writeHead(200, {
        'Content-Type': 'text/html'
    })
    response.end(html)
    
}).listen(8888)

console.log('serve listening on 8888')

然后test.html 如下。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>MyHtml</title>
</head>
<body>
    <div>hello world</div>
    <div>don't speak</div>

    <script>
        console.log('inline js')
    </script>
</body>
</html>

test.html 中有inline js 代码,我们不希望执行inline js 代码。因为XSS 攻击就是执行的inline js 代码。那么我们可以这样做,如下。

const http = require('http')
const fs = require('fs')
const zlib = require('zlib')

http.createServer(function (request, response) {
    console.log('request come', request.url)

    const html = fs.readFileSync('test.html')
    response.writeHead(200, {
        'Content-Type': 'text/html',
        'Content-Security-Policy': 'default-src http: https:'
    })
    response.end(html)
    
}).listen(8888)

console.log('serve listening on 8888')

重启服务,刷新页面,就会发现不会执行inline js 并会在控制条打印出报错信息。

下面,我们将html 中加入一个src 它的内容请求自后台。如下。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>MyHtml</title>
</head>
<body>
    <div>hello world</div>
    <div>don't speak</div>

    <script>
        console.log('inline js')
    </script>

    <script src="/test.js"></script>
</body>
</html>

然后去改一下后台代码,如下。

const http = require('http')
const fs = require('fs')
const zlib = require('zlib')

http.createServer(function (request, response) {
    console.log('request come', request.url)

    if (request.url === '/') {
        const html = fs.readFileSync('test.html')
        response.writeHead(200, {
            'Content-Type': 'text/html',
            'Content-Security-Policy': 'default-src http: https:'
        })
        response.end(html)
    } else {
        response.writeHead(200, {
            'Content-Type': 'application/javascript'
        })
        response.end('console.log("loaded script")')
    }
    
    
}).listen(8888)

console.log('serve listening on 8888')

我们重启服务,刷新页面就可以看到:

 

不仅如此,我们还可以限制,通过外部链接加载的js 文件,它可以通过哪些域名进行加载。比如限制,只能根据本域名下的js 进行加载,如下。

const http = require('http')
const fs = require('fs')
const zlib = require('zlib')

http.createServer(function (request, response) {
    console.log('request come', request.url)

    if (request.url === '/') {
        const html = fs.readFileSync('test.html')
        response.writeHead(200, {
            'Content-Type': 'text/html',
            'Content-Security-Policy': 'default-src \'self\''
            // cannot inline js
            // 'Content-Security-Policy': 'default-src http: https:'
        })
        response.end(html)
    } else {
        response.writeHead(200, {
            'Content-Type': 'application/javascript'
        })
        response.end('console.log("loaded script")')
    }
    
    
}).listen(8888)

console.log('serve listening on 8888')

然后,我们在test.html  中加入一个外链script (不同域),如下。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>MyHtml</title>
</head>
<body>
    <div>hello world</div>
    <div>don't speak</div>

    <script>
        console.log('inline js')
    </script>

    <script src="/test.js"></script>

    <script src="https://cdn.bootcss.com/jquery/3.4.1/core.js"></script>
</body>
</html>

重启,刷新后,发现:

当然,也可以设置有些域名的js 外链可访问,如下。

const http = require('http')
const fs = require('fs')
const zlib = require('zlib')

http.createServer(function (request, response) {
    console.log('request come', request.url)

    if (request.url === '/') {
        const html = fs.readFileSync('test.html')
        response.writeHead(200, {
            'Content-Type': 'text/html',
            'Content-Security-Policy': 'default-src \'self\' https://cdn.bootcss.com/'
            // cannot inline js
            // 'Content-Security-Policy': 'default-src http: https:'
        })
        response.end(html)
    } else {
        response.writeHead(200, {
            'Content-Type': 'application/javascript'
        })
        response.end('console.log("loaded script")')
    }
    
    
}).listen(8888)

console.log('serve listening on 8888')

我们还可以限制form 表单的提交方向。form 表单不接受default-src 的限制.设置如下。

const http = require('http')
const fs = require('fs')
const zlib = require('zlib')

http.createServer(function (request, response) {
    console.log('request come', request.url)

    if (request.url === '/') {
        const html = fs.readFileSync('test.html')
        response.writeHead(200, {
            'Content-Type': 'text/html',
            'Content-Security-Policy': 'default-src \'self\'; form-action \'self\''
            // 'Content-Security-Policy': 'default-src \'self\' https://cdn.bootcss.com/'
            // cannot inline js
            // 'Content-Security-Policy': 'default-src http: https:'
        })
        response.end(html)
    } else {
        response.writeHead(200, {
            'Content-Type': 'application/javascript'
        })
        response.end('console.log("loaded script")')
    }
    
    
}).listen(8888)

console.log('serve listening on 8888')

test.html 如下。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>MyHtml</title>
</head>
<body>
    <div>hello world</div>
    <div>don't speak</div>
    <form action="http://www.baidu.com">
        <input type="text" name="name" />
        <input type="submit" />
    </form>
    <script>
        console.log('inline js')
    </script>

    <script src="/test.js"></script>

    <script src="https://cdn.bootcss.com/jquery/3.4.1/core.js"></script>
</body>
</html>

注意:default-src 是将所有的src 属性限制了,包括 img 的src 。如果只想限制js 的src ,可以将default-src 改为 script-src .

汇报

内容安全策略当出现了,我们不希望出现的情况的时候,我们可以申请它向服务器发送一个请求来进行汇报。如下。

const http = require('http')
const fs = require('fs')
const zlib = require('zlib')

http.createServer(function (request, response) {
    console.log('request come', request.url)

    if (request.url === '/') {
        const html = fs.readFileSync('test.html')
        response.writeHead(200, {
            'Content-Type': 'text/html',
            'Content-Security-Policy': 'default-src \'self\'; form-action \'self\'; report-uri /report'
            // 'Content-Security-Policy': 'default-src \'self\' https://cdn.bootcss.com/'
            // cannot inline js
            // 'Content-Security-Policy': 'default-src http: https:'
        })
        response.end(html)
    } else {
        response.writeHead(200, {
            'Content-Type': 'application/javascript'
        })
        response.end('console.log("loaded script")')
    }
    
    
}).listen(8888)

console.log('serve listening on 8888')

重启刷新,会发现,network 中会发送 report 请求。

我们同时,还可以不阻止src,只是发送report ,如下。

const http = require('http')
const fs = require('fs')
const zlib = require('zlib')

http.createServer(function (request, response) {
    console.log('request come', request.url)

    if (request.url === '/') {
        const html = fs.readFileSync('test.html')
        response.writeHead(200, {
            'Content-Type': 'text/html',
            'Content-Security-Policy-Report-Only': 'default-src \'self\'; form-action \'self\'; report-uri /report'
            // 'Content-Security-Policy': 'default-src \'self\'; form-action \'self\'; report-uri /report'
            // 'Content-Security-Policy': 'default-src \'self\' https://cdn.bootcss.com/'
            // cannot inline js
            // 'Content-Security-Policy': 'default-src http: https:'
        })
        response.end(html)
    } else {
        response.writeHead(200, {
            'Content-Type': 'application/javascript'
        })
        response.end('console.log("loaded script")')
    }
    
    
}).listen(8888)

console.log('serve listening on 8888')

 

### CSP语句的用法与安全策略 #### 什么是CSP? 内容安全策略(Content Security Policy, 简称 CSP)是一种浏览器支持的安全机制,旨在减少和报告XSS(跨站脚本攻击)、点击劫持以及其他代码注入攻击的风险。通过定义一个白名单来控制页面可以加载哪些资源,从而增强网页的安全性。 #### 如何配置CSPCSP可以通过HTTP响应头或者`<meta>`标签的方式进行配置。以下是两种主要方法: 1. **通过HTTP响应头设置** 在服务器端返回的HTTP响应头部加入如下字段: ```http Content-Security-Policy: policy ``` 其中`policy`表示具体的策略规则。 2. **通过HTML `<meta>` 标签设置** 如果无法修改服务器配置,也可以在HTML文件中使用`<meta>`标签实现相同效果: ```html <meta http-equiv="Content-Security-Policy" content="policy"> ``` #### 常见的CSP指令及其含义 以下是一些常用的CSP指令以及它们的作用[^1]: | 指令 | 描述 | |-------------------|----------------------------------------------------------------------| | `default-src` | 设置默认的源列表,适用于未指定其他特定指令的情况 | | `script-src` | 控制允许执行的JavaScript脚本来源 | | `style-src` | 控制允许使用的CSS样式来源 | | `img-src` | 控制允许加载的图像来源 | | `connect-src` | 控制允许发起Ajax请求、WebSocket连接和其他网络活动的目标地址 | | `font-src` | 控制字体文件的来源 | | `object-src` | 控制Flash或其他插件对象的来源 | | `media-src` | 控制音频和视频媒体的来源 | #### 示例:基本CSP配置 假设我们希望限制网站只能加载来自同域的脚本和样式,并阻止任何外部嵌入的内容,则可以这样配置CSP: ```http Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; ``` 这条策略意味着只有当前域名下的资源能够被加载并执行,而所有的外部脚本和样式都将被拒绝加载[^1]。 #### 解决常见问题 如果遇到因启用严格CSP而导致的功能失效情况,比如第三方API调用失败或部分UI元素显示异常等问题,可以根据具体需求调整相应的指令值。例如,为了允许某个可信CDN提供静态资源,可以在对应的src属性后面追加该CDN地址: ```http Content-Security-Policy: default-src 'self'; img-src 'self' https://cdn.example.com; ``` 这表明除了本地图片外,还接受由`https://cdn.example.com`提供的图片资源。 #### 使用OWASP工具链辅助实施CSP 对于复杂的Web项目来说,手动维护一份详尽合理的CSP可能会非常困难。此时可借助像SonarQube这样的静态代码分析工具找出潜在风险点,并结合OWASP ZAP等动态扫描器验证实际运行环境下的表现是否符合预期[^4]。 #### 注意事项 - 开发者应当始终遵循最小权限原则,即只为必要的功能开放最低限度的支持。 - 即使启用了全面细致的CSP设定也不能完全替代传统的输入校验和服务端逻辑防护措施[^3]。 ```python def check_csp_compliance(response_headers): """ A simple function to verify if the HTTP response includes a valid CSP header. Args: response_headers (dict): Dictionary of headers from an HTTP Response. Returns: bool: True if CSP is present and correctly formatted; False otherwise. """ csp_header = response_headers.get('Content-Security-Policy', '') return any(keyword in csp_header for keyword in ['default-src', 'script-src']) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值