chore(i18n,learn): processed translations (#44851)

This commit is contained in:
camperbot
2022-01-21 01:00:18 +05:30
committed by GitHub
parent f866718a3d
commit 5c868af2b8
1696 changed files with 159426 additions and 69 deletions

View File

@@ -0,0 +1,393 @@
---
id: 587d824a367417b2b2512c45
title: 匿名メッセージボード
challengeType: 4
forumTopicId: 301568
dashedName: anonymous-message-board
---
# --description--
<https://anonymous-message-board.freecodecamp.rocks/> と同様の機能を持つフルスタック JavaScript アプリを構築してください。
プロジェクトに取り組むにあたり、以下の方法のうち 1 つを用いてコードを記述します。
- [GitHub リポジトリ](https://github.com/freeCodeCamp/boilerplate-project-messageboard/)をクローンし、ローカル環境でプロジェクトを完了させる。
- [Replit 始動プロジェクト](https://replit.com/github/freeCodeCamp/boilerplate-project-messageboard)を使用して、プロジェクトを完了させる。
- 使い慣れたサイトビルダーを使用してプロジェクトを完了させる。 必ず GitHub リポジトリのすべてのファイルを取り込む。
完了したら、プロジェクトの動作デモをどこか公開の場にホストしてください。 そして、`Solution Link` フィールドでデモへの URL を送信してください。 必要に応じて、`GitHub Link` フィールドでプロジェクトのソースコードへのリンクを送信してください。
# --instructions--
1. テストおよび DB をデータベース接続文字列 (`.env` 内) に書き込む準備ができたときに、引用符なしでテストするように `NODE_ENV` を設定します。
2. `routes/api.js` でコントローラー/ハンドラーを作成し、ルーティングを処理することを推奨します。
3. `server.js` にセキュリティ機能を追加します。
`tests/2_functional-tests.js` に次のテストを記述してください。
- 新しいスレッドを作成する: `/api/threads/{board}` への POST リクエスト
- 3 つの返信を持つ最新のスレッドを 10 個表示する: `/api/threads/{board}` への GET リクエスト
- 間違ったパスワードでスレッドを削除する: 無効な `delete_password` による `/api/threads/{board}` への DELETE リクエスト
- 正しいパスワードでスレッドを削除する: 有効な `delete_password` による `/api/threads/{board}` への DELETE リクエスト
- スレッドを報告する: `/api/threads/{board}` への PUT リクエスト
- 新しい返信を作成する: `/api/replies/{board}` への POST リクエスト
- すべての返信を持つ単一のスレッドを表示する: `/api/replies/{board}` への GET リクエスト
- 間違ったパスワードで返信を削除する: 無効な `delete_password` による `/api/replies/{board}` への DELETE リクエスト
- 正しいパスワードで返信を削除する: 有効な `delete_password` による `/api/replies/{board}` への DELETE リクエスト
- 返信を報告する: `/api/replies/{board}` への PUT リクエスト
# --hints--
サンプルの URL ではなく、自分で作成したプロジェクトを提供することができます。
```js
(getUserInput) => {
assert(
!/.*\/anonymous-message-board\.freecodecamp\.rocks/.test(
getUserInput('url')
)
);
};
```
自分のサイトだけを自分のページの iFrame に読み込めるようにします。
```js
async (getUserInput) => {
const data = await fetch(getUserInput('url') + '/_api/app-info');
const parsed = await data.json();
assert.isTrue(parsed.headers['x-frame-options']?.includes('SAMEORIGIN'));
};
```
DNS プリフェッチを許可しないでください。
```js
async (getUserInput) => {
const data = await fetch(getUserInput('url') + '/_api/app-info');
const parsed = await data.json();
assert.isTrue(parsed.headers['x-dns-prefetch-control']?.includes('off'));
};
```
自分のサイトだけが、自分のページに対するリファラーを送信できるようにします。
```js
async (getUserInput) => {
const data = await fetch(getUserInput('url') + '/_api/app-info');
const parsed = await data.json();
assert.isTrue(parsed.headers['referrer-policy']?.includes('same-origin'));
};
```
`text``delete_password` を含むフォームデータを使用して、`/api/threads/{board}` への POST リクエストを送信できます。 保存されるデータベースレコードは、少なくとも `_id``text``created_on` (日付と時刻)、`bumped_on`(日付と時刻、`created_on` と同じ時刻に開始)、`reported` (ブール値)、`delete_password`、および `replies` (配列) のフィールドを持ちます。
```js
async (getUserInput) => {
const date = new Date();
const text = `fcc_test_${date}`;
const deletePassword = 'delete_me';
const data = { text, delete_password: deletePassword };
const url = getUserInput('url');
const res = await fetch(url + '/api/threads/fcc_test', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (res.ok) {
const checkData = await fetch(url + '/api/threads/fcc_test');
const parsed = await checkData.json();
try {
assert.equal(parsed[0].text, text);
assert.isNotNull(parsed[0]._id);
assert.equal(new Date(parsed[0].created_on).toDateString(), date.toDateString());
assert.equal(parsed[0].bumped_on, parsed[0].created_on);
assert.isArray(parsed[0].replies);
} catch (err) {
throw new Error(err.responseText || err.message);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
`text``delete_password`、および `thread_id` を含むフォームデータを使用して、`/api/replies/{board}` への POST リクエストを送信できます。 これにより、`bumped_on` の日付がコメントの日付に更新されます。 スレッドの `replies` 配列には、少なくとも `_id``text``created_on``delete_password`、および `reported` のプロパティを持つオブジェクトが保存されます。
```js
async (getUserInput) => {
const url = getUserInput('url');
const body = await fetch(url + '/api/threads/fcc_test');
const thread = await body.json();
const date = new Date();
const text = `fcc_test_reply_${date}`;
const delete_password = 'delete_me';
const thread_id = thread[0]._id;
const replyCount = thread[0].replies.length;
const data = { text, delete_password, thread_id };
const res = await fetch(url + '/api/replies/fcc_test', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (res.ok) {
const checkData = await fetch(`${url}/api/replies/fcc_test?thread_id=${thread_id}`);
const parsed = await checkData.json();
try {
assert.equal(parsed.replies.length, replyCount + 1);
assert.equal(parsed.replies[0].text, text);
assert.equal(parsed._id, thread_id);
assert.equal(parsed.bumped_on, parsed.replies[0].created_on);
} catch (err) {
throw new Error(err.responseText || err.message);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
`/api/threads/{board}` への GET リクエストを送信できます。 掲示板で上に上げられた最新の 10 個のスレッドと、それぞれに対する最新の 3 個の返信のみの配列が返されます。 `reported` フィールドと `delete_password` フィールドはクライアントに送信されません。
```js
async (getUserInput) => {
const url = getUserInput('url');
const res = await fetch(url + '/api/threads/fcc_test');
if (res.ok) {
const threads = await res.json();
try {
assert.equal(res.status, 200);
assert.isAtMost(threads.length, 10);
for (let i = 0; i < threads.length; i++) {
assert.containsAllKeys(threads[i], ["_id", "text", "created_on", "bumped_on", "replies"]);
assert.isAtMost(threads[i].replies.length, 3);
assert.notExists(threads[i].delete_password);
assert.notExists(threads[i].reported);
for (let j = 0; j < threads[i].replies.length; j++) {
assert.notExists(threads[i].replies[j].delete_password);
assert.notExists(threads[i].replies[j].reported);
}
}
} catch (err) {
throw new Error(err.responseText || err.message);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
`/api/replies/{board}?thread_id={thread_id}` への GET リクエストを送信できます。 すべての返信を含むスレッド全体のうち、前のテストと同じフィールドをクライアントから除外したものが返されます。
```js
async (getUserInput) => {
const url = getUserInput('url');
let res = await fetch(url + '/api/threads/fcc_test');
const threads = await res.json();
const thread_id = threads[0]._id;
res = await fetch(`${url}/api/replies/fcc_test?thread_id=${thread_id}`);
if (res.ok) {
const thread = await res.json();
try {
assert.equal(res.status, 200);
assert.isObject(thread);
assert.containsAllKeys(thread, ["_id", "text", "created_on", "bumped_on", "replies"]);
assert.isArray(thread.replies);
assert.notExists(thread.delete_password);
assert.notExists(thread.reported);
for (let i = 0; i < thread.replies.length; i++) {
assert.notExists(thread.replies[i].delete_password);
assert.notExists(thread.replies[i].reported);
}
} catch (err) {
throw new Error(err.responseText || err.message);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
`/api/threads/{board}` への DELETE リクエストを送信し、スレッドを削除するために `thread_id``delete_password` を渡すことができます。 文字列 `incorrect password` または `success` が返されます。
```js
async (getUserInput) => {
const url = getUserInput('url');
let res = await fetch(url + '/api/threads/fcc_test');
const threads = await res.json();
const thread_id = threads[0]._id;
let data = { thread_id, delete_password: "wrong_password" };
const res_invalid = await fetch(url + '/api/threads/fcc_test', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
data = { thread_id, delete_password: "delete_me" };
res = await fetch(url + '/api/threads/fcc_test', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (res.ok) {
const deleted = await res.text();
const not_deleted = await res_invalid.text();
try {
assert.equal(res.status, 200);
assert.equal(deleted, "success");
assert.equal(not_deleted, "incorrect password");
} catch (err) {
throw new Error(err.responseText || err.message);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
`/api/replies/{board}` への DELETE リクエストを送信し、`thread_id``reply_id`、および `delete_password` を渡すことができます。 文字列 `incorrect password` または `success` が返されます。 実行に成功すると、`reply_id` のテキストが `[deleted]` に変更されます。
```js
async (getUserInput) => {
const url = getUserInput('url');
const thread_data = {
text: "fcc_test_thread",
delete_password: "delete_me",
};
await fetch(`${url}/api/threads/fcc_test`, {
method: "POST",
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(thread_data)
});
let res = await fetch(`${url}/api/threads/fcc_test`);
let threads = await res.json();
const thread_id = threads[0]._id;
const reply_data = { thread_id, text: "fcc_test_reply", delete_password: "delete_me" };
await fetch(`${url}/api/replies/fcc_test`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(reply_data)
});
res = await fetch(`${url}/api/threads/fcc_test`);
threads = await res.json();
const reply_id = threads[0].replies[0]._id;
const data = { thread_id, reply_id, delete_password: "delete_me" };
res = await fetch(url + '/api/replies/fcc_test', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (res.ok) {
const deleted = await res.text();
try {
assert.equal(res.status, 200);
assert.equal(deleted, "success");
res = await fetch(`${url}/api/replies/fcc_test?thread_id=${thread_id}`);
const thread = await res.json();
assert.equal(thread._id, thread_id);
assert.equal(thread.replies[0]._id, reply_id);
assert.equal(thread.replies[0].text, "[deleted]");
} catch (err) {
throw new Error(err.responseText || err.message);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
`/api/threads/{board}` への PUT リクエストを送信し、`thread_id` を渡すことができます。 文字列 `reported` が返されます。 `thread_id``reported` の値が `true` に変更されます。
```js
async (getUserInput) => {
const url = getUserInput('url');
let res = await fetch(`${url}/api/threads/fcc_test`);
const threads = await res.json();
const report_id = threads[0]._id;
const data = { report_id };
res = await fetch(`${url}/api/threads/fcc_test`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (res.ok) {
const reported = await res.text();
try {
assert.equal(res.status, 200);
assert.equal(reported, "reported");
} catch (err) {
throw new Error(err.responseText || err.message);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
`/api/replies/{board}` への PUT リクエストを送信し、`thread_id``reply_id` を渡すことができます。 文字列 `reported` が返されます。 `reply_id``reported` の値が `true` に変更されます。
```js
async (getUserInput) => {
const url = getUserInput('url');
let res = await fetch(`${url}/api/threads/fcc_test`);
const threads = await res.json();
const thread_id = threads[0]._id;
const reply_id = threads[0].replies[0]._id;
const data = { thread_id, reply_id };
res = await fetch(`${url}/api/replies/fcc_test`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (res.ok) {
const reported = await res.text();
try {
assert.equal(res.status, 200);
assert.equal(reported, "reported");
} catch (err) {
throw new Error(err.responseText || err.message);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
10 種類の機能テストがすべて完了して、合格です。
```js
async (getUserInput) => {
const tests = await fetch(getUserInput('url') + '/_api/get-tests');
const parsed = await tests.json();
assert.isTrue(parsed.length >= 10);
parsed.forEach((test) => {
assert.equal(test.state, 'passed');
assert.isAtLeast(test.assertions.length, 1);
});
};
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,95 @@
---
id: 5e46f979ac417301a38fb932
title: ポートスキャナー
challengeType: 10
forumTopicId: 462372
helpCategory: Python
dashedName: port-scanner
---
# --description--
このプロジェクトは [Replit スターターコード](https://replit.com/github/freeCodeCamp/boilerplate-port-scanner)を使用して作業を行います。
Python カリキュラムの対話式教育コンテンツを引き続き開発中です。 現在、下記の freeCodeCamp.org YouTube チャンネルで、このプロジェクトの完了に必要なすべての知識について説明する動画をいくつか公開しています。
- [「みんなで Python」ビデオコース](https://www.freecodecamp.org/news/python-for-everybody/) (14 時間)
- [「Python を学ぶ」ビデオコース](https://www.freecodecamp.org/news/learn-python-video-course/) (10 時間)
# --instructions--
Python を使用してポートスキャンプログラムを作成してください。
`port_scanner.py` ファイルで、`target``port_range` を引数に取る `get_open_ports` という関数を作成してください。 `target` には URL または IP アドレスを指定できます。 `port_range` は、チェック対象のポート範囲の最初と最後を示す 2 つの数値のリストです。
関数呼び出しの例を次に示します。
```py
get_open_ports("209.216.230.240", [440, 445])
get_open_ports("www.stackoverflow.com", [79, 82])
```
この関数は、指定した範囲の中で開いているポートのリストを返す必要があります。
`get_open_ports` 関数はまた、オプションの 3 つ目の引数として、「詳細」モードであることを示す `True` を受け取る必要があります。 これが true に設定されている場合、関数はポートのリストの代わりに説明的な文字列を返す必要があります。
詳細モードで返される文字列の形式は次のとおりです (`{}` で囲まれたテキストは表示すべき情報を示しています)。
```bash
Open ports for {URL} ({IP address})
PORT SERVICE
{port} {service name}
{port} {service name}
```
`common_ports.py` の辞書を使用して、各ポートの正しいサービス名を取得できます。
たとえば、関数を
```py
port_scanner.get_open_ports("scanme.nmap.org", [20, 80], True)
```
ように呼び出した場合は、次を返す必要があります。
```bash
Open ports for scanme.nmap.org (45.33.32.156)
PORT SERVICE
22 ssh
80 http
```
必ず適切なスペースと改行文字を含めてください。
`get_open_ports` 関数に渡された URL が無効な場合、関数は文字列 "Error: Invalid hostname" を返す必要があります。
`get_open_ports` 関数に渡された IP アドレスが無効な場合、関数は文字列 "Error: Invalid IP address" を返す必要があります。
## 開発
`port_scanner.py` にコードを記述してください。 開発には `main.py` を使用してコードをテストすることができます。 「実行」ボタンをクリックすると `main.py` が実行されます。
## テスト
このプロジェクトの単体テストは `test_module.py` にあります。 すでに `test_module.py` から `main.py` にテストをインポートしてあります。 「実行」ボタンを押すと自動的にテストが実行されます。
## 提出
プロジェクトの URL をコピーし、freeCodeCamp に提出してください。
# --hints--
すべての Python テストに合格する必要があります。
```js
```
# --solutions--
```py
# Python challenges don't need solutions,
# because they would need to be tested against a full working project.
# Please check our contributing guidelines to learn more.
```

View File

@@ -0,0 +1,175 @@
---
id: 5e601c775ac9d0ecd8b94aff
title: セキュアなリアルタイムマルチプレイヤーゲーム
challengeType: 4
forumTopicId: 462375
dashedName: secure-real-time-multiplayer-game
---
# --description--
HTML Canvas API と [Socket.io](https://socket.io/) を使用して、<https://secure-real-time-multiplayer-game.freecodecamp.rocks/> と同様の機能を持つ 2D リアルタイムマルチプレイヤーゲームを開発します。 プロジェクトに取り組むにあたり、以下の方法のうち1つを用いてコードを記述します。
- [GitHub リポジトリ](https://github.com/freeCodeCamp/boilerplate-project-secure-real-time-multiplayer-game/)をクローンし、ローカル環境でプロジェクトを完了させる。
- [Replit 始動プロジェクト](https://replit.com/github/freeCodeCamp/boilerplate-project-secure-real-time-multiplayer-game)を使用して、プロジェクトを完了させる。
- 使い慣れたサイトビルダーを使用してプロジェクトを完了させる。 必ず GitHub リポジトリのすべてのファイルを取り込む。
完了したら、プロジェクトの動作デモをどこか公開の場にホストしてください。 そして、`Solution Link` フィールドでデモへの URL を送信してください。 必要に応じて、`GitHub Link` フィールドでプロジェクトのソースコードへのリンクを送信してください。
# --instructions--
**メモ**: ユーザーストーリーの実行には `helmet@^3.21.3` が必要です。 このため、ユーザーストーリーを実現するための情報として、Helmet の旧バージョンのドキュメントを参照する必要があります。
# --hints--
サンプルの URL ではなく、自分で作成したプロジェクトを提供することができます。
```js
(getUserInput) => {
assert(
!/.*\/secure-real-time-multiplayer-game\.freecodecamp\.rocks/.test(
getUserInput('url')
)
);
};
```
複数のプレイヤーがサーバーに接続してプレイすることができます。
```js
```
プレイヤーはそれぞれアバターを持ちます。
```js
```
各プレイヤーは、`Player.mjs``Player` クラスによって作成されるオブジェクトにより表現されます。
```js
```
各プレーヤーオブジェクトには、最低限として、固有の `id``score`、プレーヤーの現在の位置を示す `x` および `y` 座標を含める必要があります。
```js
```
ゲームには少なくとも 1 種類のコレクションアイテムがあります。 それを実装するために、`Collectible.mjs``Collectible` クラスを作成してください。
```js
```
`Collectible` クラスにより作成された各コレクションアイテムオブジェクトには、最低限として、固有の `id``value`、アイテムの現在の位置を示す `x` および `y` 座標を含める必要があります。
```js
```
プレイヤーは、WASD キーや矢印キーを使用してアバターを動かすことができます。 それを実装するために、`Player.mjs``movePlayer` メソッドを作成してください。
```js
```
`movePlayer` メソッドは、"up"、"down"、"left"、"right " のいずれかの文字列と、プレーヤーの位置を変更するピクセル量を表す数値の、2 つの引数を受け取る必要があります。 `movePlayer` は、呼び出し元のプレイヤーオブジェクトの `x` 座標と `y` 座標を調整する必要があります。
```js
```
プレーヤーのスコアを使用して、他のプレーヤーとの相対順位を計算する必要があります。 それを実装するために、`Player``calculateRank` メソッドを作成してください。
```js
```
`calculateRank` メソッドは、すべての接続中のプレイヤーを表すオブジェクトの配列を受け取り、文字列 `Rank: currentRanking/totalPlayers` を返す必要があります。 たとえば、プレイヤーが 2 人のゲームで、プレイヤー A のスコアが 3、プレイヤー B のスコアが 5 の場合、プレイヤー A の `calculateRank``Rank: 2/2` を返す必要があります。
```js
```
プレイヤーはコレクションアイテムにぶつかって接触することができます。 それを実装するために、`Player.mjs``collision` メソッドを作成してください。
```js
```
`collision` メソッドは、コレクションアイテムのオブジェクトを引数として受け取る必要があります。 プレイヤーのアバターがアイテムに接触した場合、`collision` メソッドは `true` を返す必要があります。
```js
```
すべてのプレイヤーは同期が保たれます。
```js
```
プレイヤーはいつでもゲームから離れることができます。
```js
```
クライアントによる MIME タイプの推測や参照の試行を防いでください。
```js
async (getUserInput) => {
const data = await fetch(getUserInput('url') + '/_api/app-info');
const parsed = await data.json();
assert.equal(parsed.headers['x-content-type-options'], 'nosniff');
};
```
クロスサイトスクリプティング (XSS) 攻撃を防いでください。
```js
async (getUserInput) => {
const data = await fetch(getUserInput('url') + '/_api/app-info');
const parsed = await data.json();
assert.equal(parsed.headers['x-xss-protection'], '1; mode=block');
};
```
ウェブサイトからクライアントにキャッシュされるものは何もありません。
```js
async (getUserInput) => {
const data = await fetch(getUserInput('url') + '/_api/app-info');
const parsed = await data.json();
assert.equal(parsed.headers['surrogate-control'], 'no-store');
assert.equal(
parsed.headers['cache-control'],
'no-store, no-cache, must-revalidate, proxy-revalidate'
);
assert.equal(parsed.headers['pragma'], 'no-cache');
assert.equal(parsed.headers['expires'], '0');
};
```
ヘッダーには、サイトで "PHP 7.4.3" が使用されていることを記述します。ただし実際には使用されていません (セキュリティ対策が目的です)。
```js
async (getUserInput) => {
const data = await fetch(getUserInput('url') + '/_api/app-info');
const parsed = await data.json();
assert.equal(parsed.headers['x-powered-by'], 'PHP 7.4.3');
};
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,72 @@
---
id: 5e46f983ac417301a38fb933
title: SHA-1 パスワードクラッカー
challengeType: 10
forumTopicId: 462374
helpCategory: Python
dashedName: sha-1-password-cracker
---
# --description--
このプロジェクトは [Replit スターターコード](https://replit.com/github/freeCodeCamp/boilerplate-SHA-1-password-cracker)を使用して作業を行います。
Python カリキュラムの対話式教育コンテンツを引き続き開発中です。 現在、下記の freeCodeCamp.org YouTube チャンネルで、このプロジェクトの完了に必要なすべての知識について説明する動画をいくつか公開しています。
- [「みんなで Python」ビデオコース](https://www.freecodecamp.org/news/python-for-everybody/) (14 時間)
- [「Python を学ぶ」ビデオコース](https://www.freecodecamp.org/news/learn-python-video-course/) (10 時間)
# --instructions--
パスワードはプレーンテキストで保存すべきではありません。 パスワードリストが暴露された場合に備えて、ハッシュとして保存する必要があります。 ただし、すべてのハッシュが同じように作成されるとは限りません。
このプロジェクトでは、SHA-1 を使用してハッシュ化されたパスワードの解読を試みるパスワードクラックプログラムを作成し、その作業を通じて適切なセキュリティを実現することの重要性を学びます。
パスワードの SHA-1 ハッシュを受け取り、パスワードがすでに使用されている上位 10,000 個のうちの 1 つである場合に、そのパスワードを返す関数を作成してください。 SHA-1 ハッシュがデータベースにあるパスワード「ではない」場合は、"PASSWORD NOT IN DATABASE" を返してください。
関数では、`top-10000-passwords.txt` から得られるそれぞれのパスワードをハッシュし、それらを関数に渡されたハッシュと比較する必要があります。
関数は、`use_salts` というオプションの 2 つ目の引数を受け取る必要があります。 この引数が true に設定されている場合は、`top-10000-passwords.txt` から得られる各パスワードの「前と後ろの両方」に、ファイル `known-salts.txt` から得られる各ソルト文字列を追加したうえで、ハッシュ化を行い、関数に渡されたハッシュと比較する必要があります。
関数のテストに使用できるハッシュ化されたパスワードの例を次に示します。
- `b305921a3723cd5d70a375cd21a61e60aabb84ec` は "sammy123" を返す
- `c7ab388a5ebefbf4d550652f1eb4d833e5316e3e` は "abacab" を返す
- `5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8` は "password" を返す
`use_salts``True` に設定した場合に関数のテストに使用できるハッシュ化されたパスワードの例を次に示します。
- `53d8b3dc9d39f0184144674e310185e41a87ffd5` は "superman" を返す
- `da5a4e8cf89539e66097acd2f8af128acae2f8ae` は "q1w2e3r4t5" を返す
- `ea3f62d498e3b98557f9f9cd0d905028b3b019e1` は "bubbles1" を返す
`hashlib` ライブラリをあらかじめインポートしてあります。 コードでこのライブラリを使用してみてください。 hashlib の詳細については[こちら](https://docs.python.org/3/library/hashlib.html)を参照してください。
## 開発
`password_cracker.py` にコードを記述してください。 開発には `main.py` を使用してコードをテストすることができます。 「実行」ボタンをクリックすると `main.py` が実行されます。
## テスト
このプロジェクトの単体テストは `test_module.py` にあります。 すでに `test_module.py` から `main.py` にテストをインポートしてあります。 「実行」ボタンを押すと自動的にテストが実行されます。
## 提出
プロジェクトの URL をコピーし、freeCodeCamp に提出してください。
# --hints--
すべての Python テストに合格する必要があります。
```js
```
# --solutions--
```py
# Python challenges don't need solutions,
# because they would need to be tested against a full working project.
# Please check our contributing guidelines to learn more.
```

View File

@@ -0,0 +1,136 @@
---
id: 587d824a367417b2b2512c44
title: 株価チェッカー
challengeType: 4
forumTopicId: 301572
dashedName: stock-price-checker
---
# --description--
<https://stock-price-checker.freecodecamp.rocks/> と同様の機能を持つフルスタック JavaScript アプリを構築してください。
信頼できる株価 API の利用にはすべて API キーが必要になるため、ここでは回避策を用意しました。 <https://stock-price-checker-proxy.freecodecamp.rocks/> を使用すれば、登録して自分のキーを取得しなくても最新の株価情報を得ることができます。
プロジェクトに取り組むにあたり、以下の方法のうち 1 つを用いてコードを記述します。
- [ GitHub リポジトリ](https://github.com/freeCodeCamp/boilerplate-project-stockchecker/)をクローンし、ローカル環境でプロジェクトを完了させる。
- [Replit 始動プロジェクト](https://replit.com/github/freeCodeCamp/boilerplate-project-stockchecker)を使用して、プロジェクトを完了させる。
- 使い慣れたサイトビルダーを使用してプロジェクトを完了させる。 必ず GitHub リポジトリのすべてのファイルを取り込む。
完了したら、プロジェクトの動作デモをどこか公開の場にホストしてください。 そして、`Solution Link` フィールドでデモへの URL を送信してください。 必要に応じて、`GitHub Link` フィールドでプロジェクトのソースコードへのリンクを送信してください。
# --instructions--
1. `NODE_ENV` を引用符なしの `test` に設定し、`DB` を MongoDB 接続文字列に設定します。
2. `routes/api.js` でプロジェクトを完成させるか、ハンドラー/コントローラーを作成します。
3. `server.js` にセキュリティ機能を追加します。
4. `tests/2_functional-tests.js` にすべての機能テストを作成します。
**注**: プライバシーに対する注意事項: 1 つの IP に対して 1 つの「いいね」しか受け付けないという条件があるため、IP アドレスを保存する必要があります。 一般データ保護規則などのデータプライバシー関連の法令を遵守することが重要です。 ユーザーのデータを保存するための権限を取得するという方法もありますが、データを匿名化した方がはるかに簡単です。 このチャレンジでは、データベースに保存する前に必ず IP アドレスを匿名化してください。 その方法として、データをハッシュ化する、切り詰める、IP アドレスの一部を 0 にする、などが考えられます。
次のテストを `tests/2_functional-tests.js` に記述してください。
- 1 つの株式を表示: `/api/stock-prices/` への GET リクエスト
- 1 つの株式を表示して「いいね!」をクリック: `/api/stock-prices/` への GET リクエスト
- もう一度同じ株式を表示して「いいね!」をクリック: `/api/stock-prices/` への GET リクエスト
- 2 つの株式を表示: `/api/stock-prices/` への GET リクエスト
- 2 つの株式を表示して「いいね!」をクリック: `/api/stock-prices/` への GET リクエスト
# --hints--
サンプルの URL ではなく、自分で作成したプロジェクトを提供することができます。
```js
(getUserInput) => {
assert(
!/.*\/stock-price-checker\.freecodecamp\.rocks/.test(getUserInput('url'))
);
};
```
コンテンツセキュリティポリシーを設定して、自分のサーバーからのスクリプトや CSS の読み込みのみを許可するようにしてください。
```js
async (getUserInput) => {
const data = await fetch(getUserInput('url') + '/_api/app-info');
const parsed = await data.json();
assert.isTrue(
parsed.headers['content-security-policy'].includes("script-src 'self'")
);
assert.isTrue(
parsed.headers['content-security-policy'].includes("style-src 'self'")
);
};
```
`GET` リクエストを `/api/stock-prices` に送信し、NASDAQ 株式表示記号を `stock` クエリパラメーターに渡すことができます。 返されるオブジェクトには、`stockData` というプロパティが含まれます。
```js
async (getUserInput) => {
const data = await fetch(
getUserInput('url') + '/api/stock-prices?stock=GOOG'
);
const parsed = await data.json();
assert.property(parsed, 'stockData');
};
```
`stockData` プロパティには、文字列としての `stock` 記号、数値としての `price`、数値としての `likes` が含まれています。
```js
async (getUserInput) => {
const data = await fetch(
getUserInput('url') + '/api/stock-prices?stock=GOOG'
);
const parsed = await data.json();
const ticker = parsed.stockData;
assert.typeOf(ticker.price, 'number');
assert.typeOf(ticker.likes, 'number');
assert.typeOf(ticker.stock, 'string');
};
```
また、`like` フィールドに `true` (ブール値) を渡すと、その株式の「いいね!」が増えます。 「いいね」は、1 つの IP につき 1 回のみ受け付ける必要があります。
```js
```
2 つの株式を渡した場合、返される値は 2 つの株式に関する情報を持つ配列となります。 `likes` の代わりに、両方の `stockData` オブジェクトの `rel_likes` (両株式の「いいね!」の差) を表示します。
```js
async (getUserInput) => {
const data = await fetch(
getUserInput('url') + '/api/stock-prices?stock=GOOG&stock=MSFT'
);
const parsed = await data.json();
const ticker = parsed.stockData;
assert.typeOf(ticker, 'array');
assert.property(ticker[0], 'rel_likes');
assert.property(ticker[1], 'rel_likes');
};
```
5 種類の機能テストがすべて完了して、合格です。
```js
async (getUserInput) => {
const tests = await fetch(getUserInput('url') + '/_api/get-tests');
const parsed = await tests.json();
assert.isTrue(parsed.length >= 5);
parsed.forEach((test) => {
assert.equal(test.state, 'passed');
});
};
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,63 @@
---
id: 587d8248367417b2b2512c3c
title: helmet.hsts() を使用して、HTTPS 経由でサイトにアクセスするようブラウザーに指示する
challengeType: 2
forumTopicId: 301573
dashedName: ask-browsers-to-access-your-site-via-https-only-with-helmet-hsts
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
HTTP Strict Transport Security (HSTS) は、プロトコルのダウングレード攻撃や Cookie のハイジャックからウェブサイトを保護するのに役立つウェブセキュリティポリシーです。 自分のウェブサイトが HTTPS 経由でのアクセスに対応している場合、ユーザーのブラウザーに対して、安全でない HTTP の使用を避けるよう求めることができます。 Strict-Transport-Security ヘッダーを設定することで、ブラウザーに対して、指定された期間、以降のリクエストで HTTPS を使用するよう指示します。 このポリシーは、最初のリクエスト後に発生するリクエストに対して有効になります。
# --instructions--
今後 90 日間 HTTPS を使用するように `helmet.hsts()` を設定してください。 config オブジェクト `{maxAge: timeInSeconds, force: true}` を渡してください。 変数 `ninetyDaysInSeconds = 90*24*60*60;` を作成し、 `timeInSeconds` に使用することができます。 Replit ではすでに hsts が有効になっています。 この設定を上書きするには、config オブジェクトの "force" フィールドを true に設定する必要があります。 Replit のヘッダーをインターセプトし、テストのために検査した後、復元します。
注:カスタムのウェブサイトで HTTPS を設定するには、ドメインと SSL/TLS 証明書を取得する必要があります。
# --hints--
helmet.hsts() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(data.appStack, 'hsts');
assert.property(data.headers, 'strict-transport-security');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
maxAge を 7776000 秒 (90 日) にする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.match(
data.headers['strict-transport-security'],
/^max-age=7776000;?/
);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,42 @@
---
id: 587d8248367417b2b2512c3a
title: helmet.noSnifff() を使用して、レスポンスの MIME タイプの推測を回避する
challengeType: 2
forumTopicId: 301574
dashedName: avoid-inferring-the-response-mime-type-with-helmet-nosniff
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。 ブラウザーでコンテンツまたは MIME スニッフィングを使用すると、レスポンスの `Content-Type` ヘッダーを上書きし、暗黙のコンテンツタイプを使用してデータを推測し、処理することが可能になります。 これは便利な場合もありますが、危険な攻撃につながる可能性もあります。 このミドルウェアは、X-Content-Type-Options ヘッダーを `nosniff` に設定することで、提供された `Content-Type` を回避しないようにブラウザーに指示します。
# --instructions--
サーバーで `helmet.noSniff()` メソッドを使用してください。
# --hints--
helmet.noSniff() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(data.appStack, 'nosniff');
assert.equal(data.headers['x-content-type-options'], 'nosniff');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,50 @@
---
id: 587d8249367417b2b2512c40
title: '「親」の helmet() ミドルウェアを使用して Helmet を構成する'
challengeType: 2
forumTopicId: 301575
dashedName: configure-helmet-using-the-parent-helmet-middleware
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
`app.use(helmet())` では、前に紹介したすべてのミドルウェアが自動的にインクルードされますが、`noCache()``contentSecurityPolicy()` は除外されます。しかし、必要に応じてこれらを有効にすることができます。 config オブジェクトを使用して、他のミドルウェアを個別に無効化または構成することもできます。
**例:**
```js
app.use(helmet({
frameguard: { // configure
action: 'deny'
},
contentSecurityPolicy: { // enable and configure
directives: {
defaultSrc: ["'self'"],
styleSrc: ['style.com'],
}
},
dnsPrefetchControl: false // disable
}))
```
説明の都合上、またテストのしやすさを考慮して、各ミドルウェアを別々に紹介しました。 実際のプロジェクトでは「親」の `helmet()` ミドルウェアを簡単に実装して使用できます。
# --hints--
テストはありません。説明のみのチャレンジです。
```js
assert(true);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,47 @@
---
id: 587d8249367417b2b2512c3e
title: helmet.noCache() を使用してクライアントサイドのキャッシュを無効にする
challengeType: 2
forumTopicId: 301576
dashedName: disable-client-side-caching-with-helmet-nocache
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
ウェブサイトのアップデートを行う際に、ユーザーに常に新しいバージョンをダウンロードしてもらいたい場合、クライアントのブラウザーでキャッシュの無効化を行う (または試みる) ことができます。 これは開発の場合にも役立ちます。 キャッシュにはパフォーマンス上の利点がありますが、それを失うことになるため、このオプションは本当に必要な場合にのみ使用してください。
# --instructions--
サーバーで `helmet.noCache()` メソッドを使用してください。
# --hints--
helmet.noCache() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(data.appStack, 'nocache');
assert.equal(
data.headers['cache-control'],
'no-store, no-cache, must-revalidate, proxy-revalidate'
);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,44 @@
---
id: 587d8248367417b2b2512c3d
title: helmet.dnsPrefetchControl() を使用して DNS プリフェッチを無効にする
challengeType: 2
forumTopicId: 301577
dashedName: disable-dns-prefetching-with-helmet-dnsprefetchcontrol
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
ほとんどのブラウザーでは、パフォーマンスを向上させるために、ページ内のリンクの DNS レコードを先読み (プリフェッチ) します。 これにより、ユーザーがリンクをクリックしたときには、すでに目的の IP がわかっている状態になります。 その結果、DNS サービスの過度の使用 (何百万人もの人が訪れる大規模なウェブサイトの運営を想像してみてください…)、プライバシーの問題 (特定のページを閲覧しているユーザーを盗聴者が推測できる可能性がある)、ページ統計の改ざん (リンク先が訪問されていなくても訪問されているように表示される) などが発生する可能性があります。 高度なセキュリティを必要とする場合は、パフォーマンスの低下を犠牲にして、DNS プリフェッチを無効にすることができます。
# --instructions--
サーバーで `helmet.dnsPrefetchControl()` メソッドを使用してください。
# --hints--
helmet.dnsPrefetchControl() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(data.appStack, 'dnsPrefetchControl');
assert.equal(data.headers['x-dns-prefetch-control'], 'off');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,81 @@
---
id: 58a25bcff9fc0f352b528e7d
title: パスワードを非同期的にハッシュ化して比較する
challengeType: 2
forumTopicId: 301578
dashedName: hash-and-compare-passwords-asynchronously
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-bcrypt) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-bcrypt/) からクローンされています。
ハッシュは計算量が多くなるように設計されているので、ハッシュ処理中に接続がブロックされないように、サーバー上で非同期的に処理することをお勧めします。 次の呼び出しを実行するだけで、パスワードを非同期にハッシュ化できます。
```js
bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => {
/*Store hash in your db*/
});
```
# --instructions--
このハッシュ関数をサーバーに追加し (関数内で使用されている変数はすでに定義してあります)、コンソールに出力して確認してください。 通常はこの時点でハッシュをデータベースに保存します。
新しい入力がハッシュと同じデータかどうかを調べる必要がある場合は、compare 関数を使用します。
```js
bcrypt.compare(myPlaintextPassword, hash, (err, res) => {
/*res == true or false*/
});
```
完了したハッシュを出力し、compare の中でコンソールに "res" と出力した後、これを既存のハッシュ関数に追加してください (compare 関数を呼び出す前にハッシュの完了を待つ必要があるため)。 コンソールにハッシュが出力され、次に 'true' と出力されるはずです。 compare 関数の 'myPlaintextPassword' を 'someOtherPlaintextPassword' に変更すると、false と表示されます。
```js
bcrypt.hash('passw0rd!', 13, (err, hash) => {
console.log(hash);
//$2a$12$Y.PHPE15wR25qrrtgGkiYe2sXo98cjuMCG1YwSI5rJW1DSJp0gEYS
bcrypt.compare('passw0rd!', hash, (err, res) => {
console.log(res); //true
});
});
```
正しいと思ったら、ページを送信してください。
# --hints--
非同期ハッシュを生成し、正しく比較する必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/server.js').then(
(data) => {
assert.match(
data,
/START_ASYNC[^]*bcrypt.hash.*myPlaintextPassword( |),( |)saltRounds( |),( |).*err( |),( |)hash[^]*END_ASYNC/gi,
'You should call bcrypt.hash on myPlaintextPassword and saltRounds and handle err and hash as a result in the callback'
);
assert.match(
data,
/START_ASYNC[^]*bcrypt.hash[^]*bcrypt.compare.*myPlaintextPassword( |),( |)hash( |),( |).*err( |),( |)res[^]*}[^]*}[^]*END_ASYNC/gi,
'Nested within the hash function should be the compare function comparing myPlaintextPassword to hash'
);
},
(xhr) => {
throw new Error(xhr.statusText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,66 @@
---
id: 58a25bcff9fc0f352b528e7e
title: パスワードを同期的にハッシュ化して比較する
challengeType: 2
forumTopicId: 301579
dashedName: hash-and-compare-passwords-synchronously
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-bcrypt) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-bcrypt/) からクローンされています。
同期的にハッシュ化することも同様に簡単ですが、サーバーサイドで高いコストをかけて使用する場合や、頻繁にハッシュ化を行う場合には遅延が発生する可能性があります。 次の呼び出しだけで、このメソッドによるハッシュ化を実行できます。
```js
var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);
```
このハッシュメソッドをコードに追加し、結果をコンソールに表示してください。 ここでも、使用されている変数はすでにサーバーで定義されているため、変数を調整する必要はありません。 非同期関数と同じパスワードをハッシュ化しているにもかかわらず、コンソールに表示される結果が異なることに気づくかもしれません。これは、ハッシュの 3 番目の文字列の最初の 22 文字を見るとわかるように、ソルトが毎回ランダムに生成されるためです。 ここで、入力されたパスワードと新しい同期ハッシュを比較するために、compareSync メソッドを使用します。
```js
var result = bcrypt.compareSync(myPlaintextPassword, hash);
```
結果は true または false のブール値になります。
# --instructions--
関数を追加し、コンソールに結果を表示して動作を確認してください。
正しいと思ったら、ページを送信してください。
# --hints--
同期ハッシュを生成し、正しく比較する必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/server.js').then(
(data) => {
assert.match(
data,
/START_SYNC[^]*hash.*=.*bcrypt.hashSync.*myPlaintextPassword( |),( |)saltRounds[^]*END_SYNC/gi,
'You should call bcrypt.hashSync on myPlaintextPassword with saltRounds'
);
assert.match(
data,
/START_SYNC[^]*result.*=.*bcrypt.compareSync.*myPlaintextPassword( |),( |)hash[^]*END_SYNC/gi,
'You should call bcrypt.compareSync on myPlaintextPassword with the hash generated in the last line'
);
},
(xhr) => {
throw new Error(xhr.statusText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,40 @@
---
id: 587d8247367417b2b2512c37
title: helmet.hidePoweredBy() を使用して危険性のある情報を隠す
challengeType: 2
forumTopicId: 301580
dashedName: hide-potentially-dangerous-information-using-helmet-hidepoweredby
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
サイトで Express を使用していることがハッカーに知られた場合、ハッカーは Express や Node の既知の脆弱性を悪用する可能性があります。 デフォルトでは、Express からリクエストが発生するたびに `X-Powered-By: Express` が送信されます。 `helmet.hidePoweredBy()` ミドルウェアを使用して X-Powered-By ヘッダーを削除してください。
# --hints--
helmet.hidePoweredBy() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(data.appStack, 'hidePoweredBy');
assert.notEqual(data.headers['x-powered-by'], 'Express');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,53 @@
---
id: 587d8247367417b2b2512c36
title: Helmet を install して require する
challengeType: 2
forumTopicId: 301581
dashedName: install-and-require-helmet
---
# --description--
これらのチャレンジに取り組むにあたり、以下の方法のうち 1 つを用いてコードを記述します。
- [GitHub リポジトリ](https://github.com/freeCodeCamp/boilerplate-infosec/)をクローンし、ローカル環境でプロジェクトを完了させる。
- [Replit 始動プロジェクト](https://replit.com/github/freeCodeCamp/boilerplate-infosec)を使用して、チャレンジを完了させる。
- 使い慣れたサイトビルダーを使用してプロジェクトを完了させる。 必ず GitHub リポジトリのすべてのファイルを取り込む。
完了したら、プロジェクトの動作デモをどこか公開の場にホストしてください。 そして、`Solution Link` フィールドでデモへの URL を送信してください。
Helmet を使用すると、さまざまな HTTP ヘッダーを設定することができ、Express アプリケーションのセキュリティを確保するのに役立ちます。
# --instructions--
これらのレッスンで使用するコードはすべて、`myApp.js`ファイルの中で、最初に示したコードの行の間に記載されています。 追加したコードを変更したり削除したりしないでください。
Helmet のバージョン `3.21.3` をインストールし、require してください。 `npm install --save-exact package@version` を使用するか、`package.json` に直接追加することで、特定のバージョンのパッケージをインストールできます。
# --hints--
`helmet` のバージョン `3.21.3``package.json` に含める必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/package.json').then(
(data) => {
const packJson = JSON.parse(data);
const helmet = packJson.dependencies.helmet;
assert(helmet === '3.21.3' || helmet === '^3.21.3');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,64 @@
---
id: 587d8247367417b2b2512c38
title: helmet.frameguard() を使用してクリックジャック攻撃のリスクを軽減する
challengeType: 2
forumTopicId: 301582
dashedName: mitigate-the-risk-of-clickjacking-with-helmet-frameguard
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
あなたのページは、あなたの同意なしに `<frame>``<iframe>` に挿入される可能性があります。 こうした可能性は、特にクリックジャック攻撃につながるおそれがあります。 クリックジャック攻撃とは、ユーザーをだまして、ユーザーが意図しているものとは違うページとやり取りさせる手法です。 これを利用し、iframe を通じて悪意のあるコンテキストでページを実行することが可能です。 こうした状況では、ハッカーによってあなたのページ上に隠れたレイヤーが配置されます。 悪意のあるスクリプトを実行するために、隠しボタンが使用されることがあります。 このミドルウェアは、X-Frame-Options ヘッダーを設定して、 サイトをフレーム内に配置できるユーザーを制限します。 DENY、SAMEORIGIN、ALLOW-FROM の 3 つのモードがあります。
サンプルのアプリをフレームに配置する必要はありません。
# --instructions--
`helmet.frameguard()` を使用し、config オブジェクト `{action: 'deny'}` を渡してください。
# --hints--
helmet.frameguard() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(
data.appStack,
'frameguard',
'helmet.frameguard() middleware is not mounted correctly'
);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
helmet.frameguard() の 'action' を 'DENY' に設定する必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.property(data.headers, 'x-frame-options');
assert.equal(data.headers['x-frame-options'], 'DENY');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,51 @@
---
id: 587d8247367417b2b2512c39
title: >-
helmet.xssFilter() を使用してクロスサイトスクリプティング (XSS) 攻撃のリスクを軽減する
challengeType: 2
forumTopicId: 301583
dashedName: mitigate-the-risk-of-cross-site-scripting-xss-attacks-with-helmet-xssfilter
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
クロスサイトスクリプティング (XSS) はよくある攻撃の一種で、セッションの cookie やパスワードなどの機密データを盗む目的で、悪意のあるスクリプトを脆弱なページに挿入するものです。
XSS 攻撃のリスクを軽減するための基本的なルールはシンプルで、「ユーザーの入力を決して信用しない」ことです。 開発者は外部からのすべての入力を常にサニタイズ (洗浄) する必要があります。 そうした入力には、フォームからのデータ、GET クエリ URL からのデータ、さらには POST ボディからのデータなどがあります。 サニタイズとは、&lt;、> といったの危険性のある文字を検出してエンコードすることです。
最新のブラウザーでは、より優れたソフトウェア戦略が採用されており、リスクの軽減に役立つ可能性があります。 多くの場合、それらは http ヘッダーを介して設定できます。
X-XSS-Protection HTTP ヘッダーは、基本的な保護機能です。 ブラウザーは、ヒューリスティック (発見的) フィルターを使用して、挿入される可能性のあるスクリプトを検出します。 このヘッダーが有効であると、ブラウザーによってスクリプトコードが変更され、コードが無害化されます。 ただし、サポートはまだ限定的です。
# --instructions--
`helmet.xssFilter()` を使用して、サーバーに送信される入力をサニタイズしてください。
# --hints--
helmet.xssFilter() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(data.appStack, 'xXssProtection');
assert.property(data.headers, 'x-xss-protection');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,44 @@
---
id: 587d8248367417b2b2512c3b
title: helmet.ieNoOpen() を使用して、IE が信頼できない HTML を開けないようにする
challengeType: 2
forumTopicId: 301584
dashedName: prevent-ie-from-opening-untrusted-html-with-helmet-ienoopen
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
一部のウェブアプリケーションでは、信頼されていない HTML をダウンロード用に提供しています。 Internet Explorer の一部のバージョンではデフォルトで、あなたのサイトのコンテキストで、こうした HTML ファイルを開きます。 つまり、あなたのページのコンテキストで、信頼されていない HTML ページが悪意のある動作を始める可能性があります。 このミドルウェアは、X-Download-Options ヘッダーを設定して、そうしたファイルを開かないようにします。 これにより、IE ユーザーは信頼されたサイトのコンテキストでダウンロードを実行できなくなります。
# --instructions--
サーバーで `helmet.ieNoOpen()` メソッドを使用してください。
# --hints--
helmet.ieNoOpen() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(data.appStack, 'ienoopen');
assert.equal(data.headers['x-download-options'], 'noopen');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,71 @@
---
id: 587d8249367417b2b2512c3f
title: helmet.contentSecurityPolicy() を使用してコンテンツセキュリティポリシーを設定する
challengeType: 2
forumTopicId: 301585
dashedName: set-a-content-security-policy-with-helmet-contentsecuritypolicy
---
# --description--
注意点として、このプロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-infosec) にある次のスタータープロジェクトをベースに構築されているか、または [GitHub](https://github.com/freeCodeCamp/boilerplate-infosec/) からクローンされています。
このチャレンジでは、最新のブラウザーでさまざまなタイプの攻撃のリスクや影響を大幅に軽減することができる、新しい有望な防御方法を紹介します。 コンテンツセキュリティポリシー (CSP) を設定および構成すると、意図しないものがページに挿入されるのを防ぐことができます。 これにより、XSS の脆弱性、望ましくないトラッキング、悪意のあるフレームなどのさまざまな攻撃からアプリが保護されます。 CSP を機能させるには、信頼できるコンテンツソースの許可リストを定義します。 これらは、ウェブページが必要とするリソースの種類ごと (スクリプト、スタイルシート、フォント、フレーム、メディアなど) に構成できます。 複数のディレクティブを利用できるため、ウェブサイトの所有者はきめ細かい制御が可能です。 詳細については、HTML 5 Rocks、KeyCDN を参照してください。 残念ながら、CSP は古いブラウザではサポートされていません。
デフォルトでは、ディレクティブは制限が緩く設定されているため、defaultSrc ディレクティブをフォールバックとして設定することが重要です。 Helmet は、defaultSrc と default-src の両方の命名スタイルをサポートしています。 フォールバックは、指定されていないほとんどのディレクティブに適用されます。
# --instructions--
この課題では `helmet.contentSecurityPolicy()` を使用してください。 `directives` オブジェクトを追加してポリシーを構成してください。 オブジェクトの中で、`defaultSrc``["'self'"]` に設定し (ソースの許可リストは配列である必要があります)、デフォルトで自分のウェブサイトのアドレスだけを信頼するようにしてください。 また、`scriptSrc` ディレクティブを設定して、自分のウェブサイト (`'self'`) とドメイン `'trusted-cdn.com'` からのスクリプトのダウンロードのみを許可してください。
ヒント: `'self'` キーワードでは、シングルクォートがキーワード自体の一部となっているため、有効にするにはダブルクォートで囲む必要があります。
# --hints--
helmet.contentSecurityPolicy() ミドルウェアを正しくマウントする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
assert.include(data.appStack, 'csp');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
csp の config は正しくありません。 defaultSrc を ["'self'"] にし、scriptSrc を ["'self'", 'trusted-cdn.com'] にする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/app-info').then(
(data) => {
var cspHeader = Object.keys(data.headers).filter(function (k) {
return (
k === 'content-security-policy' ||
k === 'x-webkit-csp' ||
k === 'x-content-security-policy'
);
})[0];
assert.equal(
data.headers[cspHeader],
"default-src 'self'; script-src 'self' trusted-cdn.com"
);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,72 @@
---
id: 58a25bcef9fc0f352b528e7c
title: BCrypt ハッシュを理解する
challengeType: 2
forumTopicId: 301586
dashedName: understand-bcrypt-hashes
---
# --description--
以降のチャレンジについては、以前のチャレンジとは異なる新しいスタータープロジェクトで作業します。 新しいスタータープロジェクトは [Replit](https://replit.com/github/freeCodeCamp/boilerplate-bcrypt) にあります。または [GitHub](https://github.com/freeCodeCamp/boilerplate-bcrypt/) からクローンできます。
BCrypt ハッシュは非常に安全です。 ハッシュは、基本的には元のデータのフィンガープリントであり、常に一意です。 元のデータをアルゴリズムに入力し、固定長の結果を返すことで実現しています。 このプロセスをさらに複雑にして安全性を高めるため、ハッシュをソルト (*salt*) することもできます。 ハッシュをソルトするには、ハッシュ処理の前にランダムなデータを元のデータに追加する必要があります。これにより、ハッシュの解読がさらに困難になります。
BCrypt のハッシュは、常に `$2a$13$ZyprE5MRw2Q3WpNOGZWGbeG7ADUre1Q8QO.uUUtcbqloU0yvzavOm` のような構造になります。 データの先頭の小さなビット `$2a` は、どのようなハッシュアルゴリズムが使用されたかを定義しています。 次の部分 `$13` は*コスト*を定義しています。 コストとは、ハッシュの計算に必要となる処理能力のことです。 コストは 2 の累乗の対数スケールで示され、データが何回ハッシュアルゴリズムを通過するかを決定します。 たとえば、コストが 10 の場合は平均的なコンピュータで 1 秒間に 10 個のパスワードをハッシュ化できますが、コストが 15 の場合は 1 回のハッシュ化に 3 秒かかり、さらにコストが 31 の場合は 1 回のハッシュ化の完了に数日かかることになります。 現時点では、コスト 12 が非常に安全だと考えられています。 ハッシュの最後の部分 `$ZyprE5MRw2Q3WpNOGZWGbeG7ADUre1Q8QO.uUUtcbqloU0yvzavOm` は、数字、ピリオド、文字からなる 1 つの大きな文字列のように見えますが、実際には 2 つの別々の情報です。 最初の 22 文字はプレーンテキストのソルトで、残りはハッシュ化されたパスワードです。
# --instructions--
BCrypt の使用を始めるため、BCrypt を依存関係としてプロジェクトに追加し、サーバーで 'bcrypt' として require してください。
`server.js`ファイルの中に、これらのレッスンで使用するすべてのコードを最初に示したコードの間に追加してください。 追加したコードを変更したり削除したりしないでください。
正しいと思ったら、ページを送信してください。
# --hints--
BCrypt を依存関係にする必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/package.json').then(
(data) => {
var packJson = JSON.parse(data);
assert.property(
packJson.dependencies,
'bcrypt',
'Your project should list "bcrypt" as a dependency'
);
},
(xhr) => {
throw new Error(xhr.statusText);
}
);
```
BCrypt を正しく require する必要があります。
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/server.js').then(
(data) => {
assert.match(
data,
/bcrypt.*=.*require.*('|")bcrypt('|")/gi,
'You should correctly require and instantiate socket.io as io.'
);
},
(xhr) => {
throw new Error(xhr.statusText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```

View File

@@ -0,0 +1,34 @@
---
id: 5ea9997bbec2e9bc47e94db0
title: TCP クライアントの作成
challengeType: 11
videoId: ugYfJNTawks
bilibiliIds:
aid: 933058124
bvid: BV16M4y1g7zL
cid: 409034338
dashedName: creating-a-tcp-client
---
# --question--
## --text--
クライアントが一度に受け取る最大データ量を設定できるソケットオブジェクトメソッドはどれですか?
## --answers--
`.recv(1024)`
---
`.decode('ascii')`
---
`.connect(host, port)`
## --video-solution--
1

View File

@@ -0,0 +1,47 @@
---
id: 5ea9997bbec2e9bc47e94db3
title: バナー取得の開発
challengeType: 11
videoId: CeGW761BIsA
bilibiliIds:
aid: 633014533
bvid: BV1Sb4y127H9
cid: 409036288
dashedName: developing-a-banner-grabber
---
# --question--
## --text--
次の空欄を埋めて `banner` 関数を完成させてください。
```py
def banner(ip, port):
s = socket.socket()
s.__A__((ip, __B__))
print(s.recv(1024))
```
## --answers--
A: `connect`
B: `port`
---
A: `getsockname`
B: `'1-1024'`
---
A: `connect`
B: `int(port)`
## --video-solution--
3

View File

@@ -0,0 +1,34 @@
---
id: 5ea9997bbec2e9bc47e94db4
title: ポートスキャンの開発
challengeType: 11
videoId: z_qkqZS7KZ4
bilibiliIds:
aid: 208077317
bvid: BV1Uh411p7HS
cid: 409036706
dashedName: developing-a-port-scanner
---
# --question--
## --text--
`.connect()` メソッドと `.connect_ex()` メソッドの主な違いは何ですか?
## --answers--
両者のメソッドに違いはない。
---
エラーが発生した場合、またはホストが見つからなかった場合、`.connect()` はエラーコードを返すが、`.connect_ex()` は例外を発生させる。
---
エラーが発生した場合、またはホストが見つからなかった場合、`.connect()` は例外を発生させるが、`.connect_ex()` はエラーコードを返す。
## --video-solution--
3

View File

@@ -0,0 +1,34 @@
---
id: 5ea9997bbec2e9bc47e94db1
title: 'Nmap スキャンの開発: パート 1'
challengeType: 11
videoId: jYk9XaGoAnk
bilibiliIds:
aid: 805657338
bvid: BV1o34y1S7zf
cid: 414718986
dashedName: developing-an-nmap-scanner-part-1
---
# --question--
## --text--
Python 3 バージョンの `python-nmap` ライブラリをインストールするための正しいコマンドは何ですか?
## --answers--
`sudo apt install python-nmap`
---
`pip install python-nmap`
---
`pip3 install python-nmap`
## --video-solution--
3

View File

@@ -0,0 +1,34 @@
---
id: 5ea9997bbec2e9bc47e94db2
title: 'Nmap スキャンの開発: パート 2'
challengeType: 11
videoId: a98PscnUsTg
bilibiliIds:
aid: 505526943
bvid: BV1Hg411c7oE
cid: 409034761
dashedName: developing-an-nmap-scanner-part-2
---
# --question--
## --text--
21 から 443 までの UDP ポートをスキャンできるのは次のうちどれですか?
## --answers--
`.scan(ip_addr, '21-443', '-v -sU')`
---
`.scan(ip_addr, '1-1024', '-v -sS')`
---
`.scan(ip_addr, '21-443', '-v -sS')`
## --video-solution--
1

View File

@@ -0,0 +1,34 @@
---
id: 5ea9997bbec2e9bc47e94dae
title: 導入とセットアップ
challengeType: 11
videoId: XeQ7ZKtb998
bilibiliIds:
aid: 718017704
bvid: BV13Q4y1k7hX
cid: 409033630
dashedName: introduction-and-setup
---
# --question--
## --text--
Python でペネトレーションテストを開発する際に講師が推奨しているコードエディターと拡張機能はどれですか?
## --answers--
Atom と atom-python-run 拡張機能。
---
VScode と Microsoft の Python 拡張機能。
---
Sublime Text と Anaconda パッケージ。
## --video-solution--
2

View File

@@ -0,0 +1,34 @@
---
id: 5ea9997bbec2e9bc47e94daf
title: ソケットの理解と TCP サーバーの作成
challengeType: 11
videoId: F1QI9tNuDQg
bilibiliIds:
aid: 848005038
bvid: BV1bL4y1a7kJ
cid: 409034113
dashedName: understanding-sockets-and-creating-a-tcp-server
---
# --question--
## --text--
ソケットオブジェクトを生成する関数は次のうちどれですか?
## --answers--
`socket.bind((host, port))`
---
`socket.gethostbyname()`
---
`socket.socket(socket.AF_INET, socket.SOCK_STREAM)`
## --video-solution--
3