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 如下。




    
    
    
    MyHtml


    
hello world
don't speak

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 它的内容请求自后台。如下。




    
    
    
    MyHtml


    
hello world
don't speak

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

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

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

HTTP CSP_第1张图片

 

不仅如此,我们还可以限制,通过外部链接加载的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 (不同域),如下。




    
    
    
    MyHtml


    
hello world
don't speak

重启,刷新后,发现:

HTTP CSP_第2张图片

当然,也可以设置有些域名的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 如下。




    
    
    
    MyHtml


    
hello world
don't speak

注意: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')

 

你可能感兴趣的:(HTTP)