자바 스크립트로드 및 SHA-256


14

이것은 실제 응용 프로그램과 함께 코드 골프 퍼즐입니다. 다음과 같은 URL을 입력하면 일부 최신 브라우저

data:text/html,<script>alert("hi")</script>

주어진 JavaScript 코드를 실행합니다. 이제 (의사 코드)와 같은 URL이 있다고 가정하십시오.

data:text/html,<script>
    myPublicKey="12345678";
    cryptoLib=download("http://example.com/somecryptolib.js");
    if(sha256sum(cryptoLib) == "12345678")
        eval(cryptoLib)
</script>

명함에 이것을 QR 코드 로 인쇄 하면 적절한 브라우저를 사용하여 해당 URL을 방문한 사용자는 아무것도 설치할 필요없이 공개 키가 사전로드 된 공개 키 암호화 클라이언트를 얻게됩니다. 해시 확인으로 인해 ISP 가 트래픽에 방해가 되더라도 실제 암호화 소프트웨어를 사용했다고 확신 할 수 있습니다 .

불행하게도,이 의사 코드의 실제 버전은 QR 코드에 비해 상당히 길다. 내 도전은 : 얼마나 짧게 만들 수 있습니까? 구현은 다음과 같습니다.

  • Chrome 및 Firefox의 주소 표시 줄에서 올바르게 실행되는 data : ... URL이어야합니다. (유효한 데이터를 만들려면 : URL, %를 % 25로 인코딩하고 줄 바꿈을 제거해야합니다)
  • URL과 SHA-256 해시가 포함되어 있어야하며 처음에 일반 텍스트 문자열 리터럴로 사용하는 것이 좋습니다.
  • XMLHttpRequest (또는 유사한 API)를 사용하여 URL에서 파일을 다운로드하십시오 . (이 기능을 사용하려면 서버에 Access-Control-Allow-Origin : * 헤더가 포함되어 있어야합니다.)
  • 해당 URL이 성공적으로로드되고 결과에 예상 해시가있는 파일 인 경우 eval (). 그렇지 않으면 아무것도하지 않거나 오류 메시지가 표시됩니다.
  • Chrome과 Firefox에있는 모든 내장 JavaScript 함수는 공정한 게임이지만 라이브러리를로드하는 것은 불가능합니다.
  • 가능한 적은 바이트를 사용하십시오

CryptoJS ( 축소 버전 )를 사용하여 순진한 버전을 만들었습니다 .

data:text/html,<script>
    u = 'http://localhost:8000'
    h = '5e3f73c606a82d68ef40f9f9405200ce24adfd9a4189c2bc39015345f0ee46d4'
    // Insert CryptoJS here
    r = new XMLHttpRequest;
    r.open('GET', u, false);
    r.send();
    if(CryptoJS.SHA256(r.response) == h)
        eval(r.response);
</script>

축소 기에서 나오는 것은 다음과 같습니다.

data:text/html,<script>u="http://localhost:8000";h="5e3f73c606a82d68ef40f9f9405200ce24adfd9a4189c2bc39015345f0ee46d4";var CryptoJS=CryptoJS||function(k,w){var f={},x=f.lib={},g=function(){},l=x.Base={extend:function(a){g.prototype=this;var c=new g;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},t=x.WordArray=l.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=w?c:4*a.length},toString:function(a){return(a||y).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%254)for(var e=0;e<a;e++)c[b+e>>>2]|=(d[e>>>2]>>>24-8*(e%254)&255)<<24-8*((b+e)%254);else if(65535<d.length)for(e=0;e<a;e+=4)c[b+e>>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<32-8*(c%254);a.length=k.ceil(c/4)},clone:function(){var a=l.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d<a;d+=4)c.push((1<<30)*4*k.random()|0);return new t.init(c,a)}}),z=f.enc={},y=z.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++){var e=c[b>>>2]>>>24-8*(b%254)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b+=2)d[b>>>3]|=parseInt(a.substr(b,2),16)<<24-4*(b%258);return new t.init(d,c/2)}},m=z.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++)d.push(String.fromCharCode(c[b>>>2]>>>24-8*(b%254)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b++)d[b>>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%254);return new t.init(d,c)}},n=z.Utf8={stringify:function(a){try{return decodeURIComponent(escape(m.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return m.parse(unescape(encodeURIComponent(a)))}},B=x.BufferedBlockAlgorithm=l.extend({reset:function(){this._data=new t.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=n.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?k.ceil(f):k.max((f|0)-this._minBufferSize,0);a=f*e;b=k.min(4*a,b);if(a){for(var p=0;p<a;p+=e)this._doProcessBlock(d,p);p=d.splice(0,a);c.sigBytes-=b}return new t.init(p,b)},clone:function(){var a=l.clone.call(this);a._data=this._data.clone();return a},_minBufferSize:0});x.Hasher=B.extend({cfg:l.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){B.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(c,d){return(new a.init(d)).finalize(c)}},_createHmacHelper:function(a){return function(c,d){return(new A.HMAC.init(a,d)).finalize(c)}}});var A=f.algo={};return f}(Math);(function(k){for(var w=CryptoJS,f=w.lib,x=f.WordArray,g=f.Hasher,f=w.algo,l=[],t=[],z=function(a){return (1<<30)*4*(a-(a|0))|0},y=2,m=0;64>m;){var n;a:{n=y;for(var B=k.sqrt(n),A=2;A<=B;A++)if(!(n%25A)){n=!1;break a}n=!0}n&&(8>m&&(l[m]=z(k.pow(y,0.5))),t[m]=z(k.pow(y,1/3)),m++);y++}var a=[],f=f.SHA256=g.extend({_doReset:function(){this._hash=new x.init(l.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],p=b[2],k=b[3],s=b[4],l=b[5],m=b[6],n=b[7],q=0;64>q;q++){if(16>q)a[q]=c[d+q]|0;else{var v=a[q-15],g=a[q-2];a[q]=((v<<25|v>>>7)^(v<<14|v>>>18)^v>>>3)+a[q-7]+((g<<15|g>>>17)^(g<<13|g>>>19)^g>>>10)+a[q-16]}v=n+((s<<26|s>>>6)^(s<<21|s>>>11)^(s<<7|s>>>25))+(s&l^~s&m)+t[q]+a[q];g=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&p^f&p);n=m;m=l;l=s;s=k+v|0;k=p;p=f;f=e;e=v+g|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+p|0;b[3]=b[3]+k|0;b[4]=b[4]+s|0;b[5]=b[5]+l|0;b[6]=b[6]+m|0;b[7]=b[7]+n|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes;d[e>>>5]|=128<<24-e%2532;d[(e+64>>>9<<4)+14]=k.floor(b/(1<<30)*4);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=g.clone.call(this);a._hash=this._hash.clone();return a}});w.SHA256=g._createHelper(f);w.HmacSHA256=g._createHmacHelper(f)})(Math);r=new XMLHttpRequest;r.open("GET",u,!1);r.send();CryptoJS.SHA256(r.response)==h&&eval(r.response)</script> 

이 최소한의 Python 서버로 테스트했습니다.

import BaseHTTPServer

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_HEAD(s):
        s.send_response(200)
        s._sendHeaders()
        s.end_headers()
    def do_GET(s):
        s.send_response(200)
        s._sendHeaders()
        s.end_headers()
        s.wfile.write('alert("Success!")')
    def _sendHeaders(s):
        s.send_header("Content-type", "script/javascript");
        s.send_header("Access-Control-Allow-Origin", "*");

def run(server_class=BaseHTTPServer.HTTPServer,
    handler_class=RequestHandler):
    server_address = ('', 8000)
    httpd = server_class(server_address, handler_class)
    httpd.serve_forever()

run()

JavaScript 부분은 4700 바이트이지만 훨씬 더 작을 수 있습니다. 얼마나 작아 질 수 있습니까?


흥미로운 질문입니다. 서버에서 클라이언트로 eval암호화 라이브러리를 보낸 다음 암호화 라이브러리가로드 된 상태에서 두 번째 요청을하면이 점이 맞지 않습니까? 나는 해결책을 연구하는 데 시간을 보냈고 결국 그 일을 끝내었지만 문제가되는 암호 라이브러리를 엉망으로 만들지 않도록 ISP를 신뢰한다는 것을 깨달았습니다.
JayQuerie.com

권리; 안전을 위해 첫 번째로로드 된 파일은 완전히 URL에있는 코드를 사용하여 해시를 검증해야합니다. 운 좋게도 이것은 하나의 해시 함수 (필요하지만 SHA-256 일 필요는 없음) 만 필요합니다. 이는 순진하게 4700 바이트였으며 아마도 최적화가 높으면 <1kb 일 수 있습니다. (그러면 더 이상 URL에 포함되지 않기 때문에 크기가 중요하지 않은 더 큰 라이브러리의로드 및 확인을 처리합니다.)
jimrandomh

"라이브러리로드가 불가능합니다." - script요소 를 생성 하고 async속성을 설정하고 false문서에 삽입하는 등 코드에서 수행해야하는 경우를 제외하고 라이브러리를로드하지 않아야 합니까?
John Dvorak

2
@ JanDvorak, 그러나 라이브러리가 수정되지 않았 음을 어떻게 확인합니까?
Peter Taylor

script/javascript? 당신은 의미 text/javascript합니다.
nyuszika7h

답변:


6

844 자

K=new XMLHttpRequest;K.open("get","http://localhost:8000",O=j=n=q=0);K.send();m=K.response;l=m.length;k=l+1|63;W=[o=Math.pow];for(H=[R=o(i=2,32)];i<313+l;i++)for(W[i]||(K[q]=o(i,1/3)*R|0,H[q++]=o(i,.5)*R|0,I=2);W[i*I++]=199>I;)o[n>>2]|=(n^l?m.charCodeAt(n):128)<<24-n++%4*8;for(o[k>>2]=8*l;j<=k;H[I-7]+=a=t+T|0)i=j++&63||(a=H[0],b=H[1],c=H[2],d=H[3],e=H[4],f=H[5],g=H[6],h=H[7],0),y=W[i-15],x=W[i-2],t=h+(e<<26^e>>>6^e<<21^e>>>11^e<<7^e>>>25)+(e&f^~e&g)+K[i]+(W[i]=16>i?o[O++]:(y<<25^y>>>7^y<<14^y>>>18^y>>>3)+W[i-7]+(x<<15^x>>>17^x<<13^x>>>19^x>>>10)+W[i-16]),T=(a<<30^a>>>2^a<<19^a>>>13^a<<10^a>>>22)+(a&b^a&c^b&c),H[I=i-63|7]+=h=g,H[I-1]+=g=f,H[I-2]+=f=e,H[I-3]+=e=d+t|0,H[I-4]+=d=c,H[I-5]+=c=b,H[I-6]+=b=a;1581216710^H[0]|111684968^H[1]|4014012921^H[2]|1079115982^H[3]|615382426^H[4]|1099547324^H[5]|956388165^H[6]|4042147540^H[7]||eval(m)

URL 및 해시 값은 하드 코딩됩니다. 해시는 십진수 더블 워드로 인코딩되며, 내 코드의 값은 예제 Python 서버의 스크립트에 해당합니다.

또한 URL 인코딩을 귀찮게하지 않았지만 javascript:URL 표시 줄에 수동으로 입력 한 다음 코드를 붙여 넣을 때도 콘솔에서 작동합니다.

구현은 호환되지 않지만 512MB보다 작은 파일에서는 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.