节点加密 sha256 不适用于空格
Node crypto sha256 not working with whitespace
我是不是做错了什么或者这是一个错误?
使用时
var checkSum = crypto.createHash("sha256").update(scriptInnerHTML, "utf-8").digest("base64")
为此脚本标签生成 sha256:
<script>
console.warn("works");
var some code ...
</script>
并像这样在 Content-Security-Policy 中使用它:
<meta http-equiv="Content-Security-Policy" content="script-src 'sha256-8O+YTKIDgMhMvSanTZx1Om5XY2ERB+kIxN8AcO2r6Ok='">
一切正常,但是这个除了没有警告日志外完全相同,但不起作用。请注意代码前的几行换行符和一个制表符。
<script>
var some code ...
</script>
如果后面有文本,Node 似乎会以不同的方式解释制表符(或者更确切地说是换行符+制表符)。奇怪!
在 Safari 和 Chrome 中都进行了测试,因此这应该不是浏览器问题。
更新:
我当然会为每个输入重新生成哈希。
示例:
(脚本标签在底部)
工作哈希('sha256-5++3ItSu+9maCZiuuXH60RG7EugmibMmhxhwpsynAn0='):http://aggressive.se/test/works.html
无效哈希('sha256-hIRDHGUSaEmjNiVhNabY+8l4GNQdj/PXD4XHA21gdRM='):http://aggressive.se/test/fail.html
已解决:
问题是由于 JSDom 中的 serialize() 函数,我用它在节点中生成 HTML。在计算哈希后调用 dom.serialize() ,它删除了一个不必要的选项卡,该选项卡更改了源(以一种很难注意到的方式)。
但如你所知,问题不是由节点或加密模块引起的。 (希望有人对此有用)
我不确定您是如何获得 scriptInnerHTML
变量的,但是如果我访问 fail.html
示例中感兴趣的脚本的 innerHTML
属性,我得到这个十六进制转储:
00000000 0a 0a 0a 09 76 61 72 20 6c 61 79 6f 75 74 20 3d |....var layout =|
00000010 20 6e 65 77 20 41 67 67 72 65 73 73 69 76 65 4c | new AggressiveL|
00000020 61 79 6f 75 74 28 29 3b 0a 09 41 67 67 72 65 73 |ayout();..Aggres|
00000030 73 69 76 65 4c 61 79 6f 75 74 2e 70 72 6f 74 6f |siveLayout.proto|
00000040 74 79 70 65 2e 73 65 74 75 70 46 75 6e 63 74 69 |type.setupFuncti|
00000050 6f 6e 20 3d 20 66 75 6e 63 74 69 6f 6e 28 29 0a |on = function().|
00000060 09 7b 0a 09 09 76 61 72 20 65 6c 65 6d 65 6e 74 |.{...var element|
00000070 20 3d 20 64 6f 63 75 6d 65 6e 74 2e 63 72 65 61 | = document.crea|
00000080 74 65 45 6c 65 6d 65 6e 74 28 22 64 69 76 22 29 |teElement("div")|
00000090 3b 0a 09 09 65 6c 65 6d 65 6e 74 2e 69 6e 6e 65 |;...element.inne|
000000a0 72 48 54 4d 4c 20 3d 20 22 49 74 20 77 6f 72 6b |rHTML = "It work|
000000b0 73 22 3b 0a 09 09 74 68 69 73 2e 65 6c 65 6d 65 |s";...this.eleme|
000000c0 6e 74 73 2e 72 6f 6f 74 45 6c 65 6d 65 6e 74 2e |nts.rootElement.|
000000d0 61 70 70 65 6e 64 43 68 69 6c 64 28 65 6c 65 6d |appendChild(elem|
000000e0 65 6e 74 29 0a 09 7d 0a |ent)..}.|
对应的hash为bR9Os+NBLWNZ3/wFVRhBilP05u9OeSj0ABRo+T8QF+g=
。如果我在 html 文件中使用这个散列,它似乎可以工作...
JSDOM
的例子:
const fs = require('fs');
const crypto = require('crypto');
const { JSDOM } = require('jsdom');
const dom = new JSDOM(fs.readFileSync('./fail.html'));
const data = dom.window.document.querySelector('head > script:last-child').innerHTML;
console.log(crypto.createHash('sha256').update(data, 'utf-8').digest('base64'));
//bR9Os+NBLWNZ3/wFVRhBilP05u9OeSj0ABRo+T8QF+g=
我是不是做错了什么或者这是一个错误?
使用时
var checkSum = crypto.createHash("sha256").update(scriptInnerHTML, "utf-8").digest("base64")
为此脚本标签生成 sha256:
<script>
console.warn("works");
var some code ...
</script>
并像这样在 Content-Security-Policy 中使用它:
<meta http-equiv="Content-Security-Policy" content="script-src 'sha256-8O+YTKIDgMhMvSanTZx1Om5XY2ERB+kIxN8AcO2r6Ok='">
一切正常,但是这个除了没有警告日志外完全相同,但不起作用。请注意代码前的几行换行符和一个制表符。
<script>
var some code ...
</script>
如果后面有文本,Node 似乎会以不同的方式解释制表符(或者更确切地说是换行符+制表符)。奇怪!
在 Safari 和 Chrome 中都进行了测试,因此这应该不是浏览器问题。
更新: 我当然会为每个输入重新生成哈希。
示例:
(脚本标签在底部)
工作哈希('sha256-5++3ItSu+9maCZiuuXH60RG7EugmibMmhxhwpsynAn0='):http://aggressive.se/test/works.html
无效哈希('sha256-hIRDHGUSaEmjNiVhNabY+8l4GNQdj/PXD4XHA21gdRM='):http://aggressive.se/test/fail.html
已解决: 问题是由于 JSDom 中的 serialize() 函数,我用它在节点中生成 HTML。在计算哈希后调用 dom.serialize() ,它删除了一个不必要的选项卡,该选项卡更改了源(以一种很难注意到的方式)。
但如你所知,问题不是由节点或加密模块引起的。 (希望有人对此有用)
我不确定您是如何获得 scriptInnerHTML
变量的,但是如果我访问 fail.html
示例中感兴趣的脚本的 innerHTML
属性,我得到这个十六进制转储:
00000000 0a 0a 0a 09 76 61 72 20 6c 61 79 6f 75 74 20 3d |....var layout =|
00000010 20 6e 65 77 20 41 67 67 72 65 73 73 69 76 65 4c | new AggressiveL|
00000020 61 79 6f 75 74 28 29 3b 0a 09 41 67 67 72 65 73 |ayout();..Aggres|
00000030 73 69 76 65 4c 61 79 6f 75 74 2e 70 72 6f 74 6f |siveLayout.proto|
00000040 74 79 70 65 2e 73 65 74 75 70 46 75 6e 63 74 69 |type.setupFuncti|
00000050 6f 6e 20 3d 20 66 75 6e 63 74 69 6f 6e 28 29 0a |on = function().|
00000060 09 7b 0a 09 09 76 61 72 20 65 6c 65 6d 65 6e 74 |.{...var element|
00000070 20 3d 20 64 6f 63 75 6d 65 6e 74 2e 63 72 65 61 | = document.crea|
00000080 74 65 45 6c 65 6d 65 6e 74 28 22 64 69 76 22 29 |teElement("div")|
00000090 3b 0a 09 09 65 6c 65 6d 65 6e 74 2e 69 6e 6e 65 |;...element.inne|
000000a0 72 48 54 4d 4c 20 3d 20 22 49 74 20 77 6f 72 6b |rHTML = "It work|
000000b0 73 22 3b 0a 09 09 74 68 69 73 2e 65 6c 65 6d 65 |s";...this.eleme|
000000c0 6e 74 73 2e 72 6f 6f 74 45 6c 65 6d 65 6e 74 2e |nts.rootElement.|
000000d0 61 70 70 65 6e 64 43 68 69 6c 64 28 65 6c 65 6d |appendChild(elem|
000000e0 65 6e 74 29 0a 09 7d 0a |ent)..}.|
对应的hash为bR9Os+NBLWNZ3/wFVRhBilP05u9OeSj0ABRo+T8QF+g=
。如果我在 html 文件中使用这个散列,它似乎可以工作...
JSDOM
的例子:
const fs = require('fs');
const crypto = require('crypto');
const { JSDOM } = require('jsdom');
const dom = new JSDOM(fs.readFileSync('./fail.html'));
const data = dom.window.document.querySelector('head > script:last-child').innerHTML;
console.log(crypto.createHash('sha256').update(data, 'utf-8').digest('base64'));
//bR9Os+NBLWNZ3/wFVRhBilP05u9OeSj0ABRo+T8QF+g=