⚠️ 実験的 [WIP] - ご自身の責任で使用してください(詳細)
LavaDome に挑戦してみましょう - デモアプリ を訪れ、コンソールを開き、LavaDome インスタンス内から秘密情報を盗み出すためにあらゆる手段を講じてください(成功したら 報告 してください)
今日のウェブ標準において、DOM サブツリーを安全な方法で選択的に分離する確立された方法はありません。言い換えれば、同じ JavaScript 実行環境を共有する場合、一部の関係者にはアクセスを許可し、他の関係者にはアクセスをブロックすることで、DOM のセクションへのアクセスを制御することはできません。
私たちは、自社アプリ内のコードをもはや信頼できない世界に生きています。そして、同一オリジンでの実行は安全性を保証しません。フロントエンドで秘密情報を保護するには、同一オリジンで実行される JavaScript コードによって侵害されないことを保証しつつ、ユーザーにコンテンツを提示できるようにする必要があります。

現在、この機密コンテンツは、エクスポートされると単に DOM にアタッチされるため、同じアプリで動作するすべてのエンティティが完全にアクセス可能になります。つまり、秘密鍵にアクセスすべきでないコードの部分が、平文で簡単に抽出できる可能性があります。悪意のあるコードが DOM にアクセスできる限りは。
しかし、ご安心ください。これは 解決可能な問題 であると私たちは信じています 👇
LavaDome は現在、Vanilla JavaScript と React をサポートしています(今後さらに追加予定)
import { LavaDome as LavaDomeJavaScript } from '@lavamoat/lavadome-javascript';
const root = document.getElementById('root'); const lavadome = new LavaDomeJavaScript(root); lavadome.text(secret); lavadome.copy(); // copy to clipboard
### [React](https://github.com/lavamoat/lavadome/blob/main/packages/react)```javascript
import { LavaDome as LavaDomeReact, toLavaDomeToken } from '@lavamoat/lavadome-react';
function Secret({ text }) {
const {token, copy} = toLavaDomeCapabilities(text);
return <>
<a onClick={copy}> copy to clipboard </a>
<LavaDomeReact token={token} />
</>;
}
ルートノードに加えて、すべてのコンストラクタはオプションの第2引数(options)を受け付けます:```javascript // javascript new LavaDomeJavaScript(root, { // boolean unsafeOpenModeShadow: false, });
// react function Secret({ text }) { const {token} = toLavaDomeCapabilities(text); return <LavaDomeReact token={token} // boolean unsafeOpenModeShadow={false} /> }
### 安全な使用方法
ウェブコアの制限により、LavaDome を安全に統合するには、統合する開発者による積極的な対応が必要となるいくつかの点に注意する必要があります。
#### 実行順序
LavaDome は、他の JavaScript セキュリティソフトウェアと同様に、それより前に実行されるコードに対して常に脆弱です。
つまり、完全に信頼できるコードを除き、LavaDome は Web アプリケーションプログラムで最初に読み込まれるコードでなければなりません。
これは、開発者がすぐにそれを使用しなければならないという意味ではありません(必要なときにだけ使用すればよい)が、それでもプログラムをできるだけ早く組み込む必要があります。
これを正しく(安全に)行うためには、プログラム全体で最初の import/require 宣言でなければなりません:```javascript
import '@lavamoat/lavadome-react';
import 'other-stuff';
console.log('Program starts here');
そうすることで、LavaDome が安全に使用するための準備を確実に行えるようになります。
これは @lavamoat/lavadome-react だけでなく、他の LavaDome パッケージにも同様に当てはまることに注意してください(そのため、複数をインポートする必要はありません)。
詳細は Security(defensive-coding) に移動してください。
サイドチャネリング攻撃とウェブの制限により、リモートフォントの読み込みは LavaDome に対する有効な手法になり得ます。CSS の領域に組み込まれているため、現在 LavaDome 経由でこの問題に対処することはできません。
幸い、これは CSP の font-src ディレクティブを使用して効果的に対処できます。
この種の攻撃を軽減するには、Web アプリが未知のサーバーからのフォント取得を許可しないようにしてください。
詳細は Security(side-channeling) に移動してください。
開発者が LavaDome に提供するテキストは 100% 予測不可能でなければなりません。そうでないと、攻撃されて漏洩する可能性があります。
したがって、アプリが "your key is 234789" を表示する必要がある場合、DOM 構造は次のようになる必要があります:```html
your key is 234789
また、~であってはならない:```html
<span> <lavadome>your key is 234789</lavadome> </span>
詳細は セキュリティ(発見可能性) をご覧ください。
LavaDome をテストの文脈で統合するのは厄介かもしれません。なぜなら、LavaDome は秘密を隠すのに優れているため、テストからも見事に隠してしまうからです。
LavaDome をテスト環境にうまく統合するには、@lavamoat/lavadome-core によってエクスポートされる LavaDomeDebug からの支援が必要かもしれません:```javascript
// IMPORT/USE FOR TESTING/DEBUGGING PURPOSES ONLY - NEVER IN PRODUCTION!
import { LavaDomeDebug } from '@lavamoat/lavadome-core';
以下は、`LavaDome` ベースのコンポーネントをテストする際に役立つ、`LavaDomeDebug` がエクスポートするデバッグ用ユーティリティメソッドの一部です。
#### `getTextByRoot()`
`LavaDome` が接続されたルートを指定すると、`getTextByRoot()` は内部のシークレットを再帰的に抽出して再構築します。これを可能にするには、`LavaDome` インスタンスが最初にアンセーフなオプション `@unsafeOpenModeShadow` を指定して初期化されている必要があります。これにより、`LavaDome` の内部シャドウが外部からアクセス可能になります。
当然ながら、これはアンセーフであり、`LavaDome` を完全に脆弱な状態にしますが、テスト/デバッグ目的でのみ使用するのが理にかなっています。本番環境ではこのオプションを決して有効にしないようにしてください!```javascript
new LavaDomeJavaScript(root, {
unsafeOpenModeShadow: isThisTestingEnv, // boolean
}).text('123456');
LavaDomeDebug.getTextByRoot(root) === '123456'; // true
stripDistractionFromText()Webドライバーを使用してテストし、LavaDome インスタンスのルートのinner textを抽出するように指示する場合、シークレットとLavaDomeのディストラクションテキストの両方を含む文字列が返されます。
ディストラクションテキストはセキュリティ上重要ですが(セキュリティ(サイドチャネリング)を参照)、Webドライバーがシークレットの一部ではない文字を抽出する原因となります。
これを解決するために、Webドライバーが取得したテキストが与えられると、stripDistractionFromText() はそこからディストラクションテキストを除去し、テストが期待する正確な文字列だけを残します。
ディストラクションテキストについて心配する必要はありません。アプリ内のユーザーには決して表示/操作されることはありませんが、セキュリティ上の理由から存在する必要があります。```javascript new LavaDomeJavaScript(root).text('123456'); const element = await driver.findElement('#ROOT'); // driver const text = await element.getText(); // driver LavaDomeDebug.stripDistractionFromText(text) === '123456'; // true
## 開発
**`LavaDome`** のローカル開発ビルドをセットアップするには、このリポジトリをクローンして、以下のいずれかのコマンドを実行してください:```bash
npm install && npm install --global serve
Please provide the Markdown content to translate.```bash yarn install && yarn global add serve
## 解決策
[`ShadowDom`](https://web.dev/articles/`ShadowDom`-v1) Web API を使用すると、DOM ノードを分離してカプセル化できます。[セキュリティ機能として設計されていません](https://web.dev/articles/`ShadowDom`-v1#:~:text=Note%3A%20Closed%20shadow%20roots%20are%20not%20very%20useful.%20Some%20developers%20will%20see%20closed%20mode%20as%20an%20artificial%20security%20feature.%20But%20let%27s%20be%20clear%2C%20it%27s%20not%20a%20security%20feature.for%20Closed%20mode%20simply%20prevents%20outside%20JS%20from%20drilling%20into%20an%20element%27s%20internal%20DOM.)が、`ShadowDom` は、ページ内の他の場所で実行されている JavaScript や CSS から DOM サブツリーを分離するのに適しています。
**`LavaDome`** の基本的なアプローチは、`ShadowDom` の[潜在的なセキュリティギャップ](https://blog.ankursundara.com/shadow-dom/)に慎重に対処しながら、これを活用することです。
**[LavaDome](https://github.com/lavamoat/lavadome/)** は、ユーザーおよび信頼されたコードとの対話のみを許可し、アプリ内の信頼されていない JavaScript および CSS コードによるアクセス試行をブロックする、フロントエンド専用コンポーネントを実装するための **LavaMoat ツールボックスのセキュリティツール** となることを意図しています。
> **`LavaDome`** に実装された主要なセキュリティ改善の基盤を提供した、`ShadowDom` セキュリティに関する[研究](https://blog.ankursundara.com/shadow-dom/)を行った [@arxenix](https://github.com/arxenix) に感謝します。
## 目標
**`LavaDome`** プロジェクトは、以下の核となる原則に従います。
### セキュリティ
私たちの最優先事項は、堅牢なセキュリティを提供することです。機密情報を表示する際に安全に使用できるよう、`ShadowDom` API を高度なセキュリティ特性でラップしています。
この取り組みの詳細については、[セキュリティ](#Security) をご覧ください。
### DX
私たちは、合理化された開発者体験を提供するよう努めています。そのために、以下のことを行います:
1. できるだけ多くの人気フレームワーク(React、Angular など)をサポートする;
2. API を簡単かつシンプルに使用できるようにする。
### 読み取り専用モード
現時点では、書き込みモードのサポートは計画していません。つまり、**`LavaDome`** は保護対象としてプレーンテキストコンテンツのみを受け入れ、それ以上に複雑なものは受け入れません。
これは、書き込みモードをサポートするには、扱いが難しい孤立した DOM の実装が必要であり、現時点でまだ直面する準備ができていない複数のセキュリティ上の複雑さが生じるためです。例えば: