HTTP CSP

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')

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值