x-line-signatureの署名検証についての備忘

## 背景

LINEのMessagingAPIにてWebhookを使用する際、そのリクエストがLINEからのものであるかの検証を行うため、リクエストヘッダの`x-line-signature`の署名を検証する必要がある。

公式 - 署名を検証する
https://developers.line.biz/ja/reference/messaging-api/#signature-validation

Node.jsのサンプルコードで`const crypto = require("crypto");`とあるが、`npm view crypto`で見ると非推奨

```bash
bash-3.2$ npm view crypto

crypto@1.0.1 | ISC | deps: none | versions: 4
This package is no longer supported and has been deprecated. To avoid malicious use, npm is hanging on to the package name.
https://github.com/npm/deprecate-holder#readme

DEPRECATED ⚠️  - This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.

dist
.tarball: https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz
.shasum: 2af1b7cad8175d24c8a1b0778255794a21803037
.integrity: sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==

maintainers:
- npm <npm@npmjs.com>

dist-tags:
latest: 1.0.1  

published over a year ago by ehsalazar <ernie@npmjs.com>

```

# どう対処するのか？

説明には下記の言及がある。

```bash
This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.
```

要するにNodeのネイティブパッケージとなったため、`npm install`しなくてもそのままコードの中で`import`して使ってくださいということ。

なのでLINEさんの公式ドキュメント通り実装すれば問題なし。
実際に実装したコード

```javascript
import crypto from 'crypto';

// X-Line-Signatureの検証
export const handler = async (event) => {
    try {
        // リクエストボディのダイジェストを計算
        const channelSecret = process.env['SECRET_KEY']; // Channel secret string
        const hmac = crypto.createHmac('sha256', channelSecret);
        hmac.update(event.body);
        const signature = hmac.digest('base64');

        // リクエストヘッダーのx-line-signatureに含まれる署名と一致するかどうかを確認
        if (signature !== event.headers['x-line-signature']) {
            return {
                statusCode: 401,
                body: JSON.stringify('Error Request Unauthorized')
            };
        }
        
        // 署名が一致した場合の処理
        // 他の処理をここに追加
        
    } catch (err) {
        return {
            statusCode: 500,
            body: JSON.stringify('Error verifying signature')
        };
    }
};
```

# ネイティブモジュールとは？

JavaScript で書かれている通常のモジュールとは異なり、C/C++ などのネイティブコードで記述されており、Node.js のランタイムに直接組み込まれている。これにより、パフォーマンスの向上やシステムレベルの機能へのアクセスが可能になる。

### 代表的なネイティブモジュール

1.	fs (File System)
2.	http
3.	path
4.	crypto
5.	buffer
6.	os
7.	child_process
8.	stream


# (参考情報)

`crypto-js`というnpmパッケージもあるがこちらも今後はメンテナンス予定なしのよう。
以下を見ると暗号に対して`Math.random()`が安全でない...のようなことが記載にある。

https://www.npmjs.com/package/crypto-js

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194056/9de043da-5034-08dd-8a5c-125551775221.png)


ちなみに、crypto-jsを使って書くと下記の通り


```Javascript
import CryptoJS from 'crypto-js';

// X-Line-Signatureの検証
export const handler = async (event) => {
    try {
        // リクエストボディのダイジェストを計算
        const channelSecret = process.env['SECRET_KEY']; // Channel secret string
        const hash = CryptoJS.HmacSHA256(event.body, channelSecret);
        const signature = CryptoJS.enc.Base64.stringify(hash);

        // リクエストヘッダーのx-line-signatureに含まれる署名と一致するかどうかを確認
        if (signature !== event.headers['x-line-signature']){
            return {
                statusCode: 401,
                body: JSON.stringify('Error Request Unauthorized')
            };
        };
    } catch (err) {
        return {
            statusCode: 500,
            body: JSON.stringify('Error sending message to SQS')
        };
    };
};
```

以上、備忘まででした。