ホームページ ウェブフロントエンド jsチュートリアル CORS クロスドメイン リクエストでマルチドメイン名のホワイトリストを設定するための Node.js のサンプル コード共有

CORS クロスドメイン リクエストでマルチドメイン名のホワイトリストを設定するための Node.js のサンプル コード共有

Mar 28, 2017 pm 02:34 PM

この記事では主に Node.js CORS クロスドメインリクエストでマルチドメイン名のホワイトリストを設定する方法について、サンプルコードを通して詳しく紹介しています。必要な場合はフォローすることができます。一緒に見てみましょう。

CORS

CORS について言えば、フロントエンドについては誰もがよく知っていると思うので、ここでは詳しく説明しません。詳しくは、この記事を読んでください。

CORS は主に、インターフェイスにアクセスを許可するドメイン名に対する応答ヘッダーの Access-Control-Allow-Origin 属性を構成します。最も一般的な設定は次のとおりです:

1

2

res.header('Access-Control-Allow-Origin', '*');

res.header('Access-Control-Allow-Credentials', 'true'); // 允许服务器端发送Cookie数据

ログイン後にコピー

ただし、この設定は最も単純かつ粗雑であり、最も安全性が低くなります。これは、インターフェイスがすべてのドメイン名に対してクロスドメイン リクエストを行うことを許可することを意味します。ただし、一般的な実際のビジネスでは、インターフェイスでは、すべてではなく、1 つまたは少数の Web サイトに対してクロスドメイン リクエストのアクセス許可のみを許可することが予想されます。

それでは、賢明な方であれば、通常のルールを記述するだけで複数のドメイン名をホワイトリストに登録するのは簡単ではないかと考えているはずです。それが機能しない場合は、Access-Control-Allow-Origin 属性をカンマで区切られた複数のドメイン名に直接構成する方が良いのではないでしょうか?

このように:

1

2

3

4

res.header('Access-Control-Allow-Origin', '*.666.com');

 

// 或者如下

res.header('Access-Control-Allow-Origin', 'a.666.com,b.666.com,c.666.com');

ログイン後にコピー

申し訳ありませんが、この書き方は無効です。 Node.js では、応答ヘッダーの Access-Control-Allow-Origin 属性は (*) 以外の正規表現と一致できず、ドメイン名をカンマで区切ることもできません。つまり、Access-Control-Allow-Origin の属性値は、単一のドメイン名 文字列 または (*) にのみ設定できます。 複数のドメイン名を許可する必要があり、安全でない *

ワイルドカード

を使用したくないため、複数のドメイン名ホワイトリストに対して CORS を構成できないというのは本当ですか?複数のドメイン名ホワイトリストを使用した CORS は実際に実現可能です。国を救うにはちょっとしたひねりが必要です。

マルチドメインホワイトリストのCORS実装原則

特定の原則については、corsライブラリのコアコードを参照できます:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

<strong>(function () {

 

 &#39;use strict&#39;;

 

 var assign = require(&#39;object-assign&#39;);

 var vary = require(&#39;vary&#39;);

 

 var defaults = {

 origin: &#39;*&#39;,

 methods: &#39;GET,HEAD,PUT,PATCH,POST,DELETE&#39;,

 preflightContinue: false,

 optionsSuccessStatus: 204

 };

 

 function isString(s) {

 return typeof s === &#39;string&#39; || s instanceof String;

 }

 

 function isOriginAllowed(origin, allowedOrigin) {

 if (Array.isArray(allowedOrigin)) {

 for (var i = 0; i < allowedOrigin.length; ++i) {

 if (isOriginAllowed(origin, allowedOrigin[i])) {

  return true;

 }

 }

 return false;

 } else if (isString(allowedOrigin)) {

 return origin === allowedOrigin;

 } else if (allowedOrigin instanceof RegExp) {

 return allowedOrigin.test(origin);

 } else {

 return !!allowedOrigin;

 }

 }

 

 function configureOrigin(options, req) {

 var requestOrigin = req.headers.origin,

 headers = [],

 isAllowed;

 

 if (!options.origin || options.origin === &#39;*&#39;) {

 // allow any origin

 headers.push([{

 key: &#39;Access-Control-Allow-Origin&#39;,

 value: &#39;*&#39;

 }]);

 } else if (isString(options.origin)) {

 // fixed origin

 headers.push([{

 key: &#39;Access-Control-Allow-Origin&#39;,

 value: options.origin

 }]);

 headers.push([{

 key: &#39;Vary&#39;,

 value: &#39;Origin&#39;

 }]);

 } else {

 isAllowed = isOriginAllowed(requestOrigin, options.origin);

 // reflect origin

 headers.push([{

 key: &#39;Access-Control-Allow-Origin&#39;,

 value: isAllowed ? requestOrigin : false

 }]);

 headers.push([{

 key: &#39;Vary&#39;,

 value: &#39;Origin&#39;

 }]);

 }

 

 return headers;

 }

 

 function configureMethods(options) {

 var methods = options.methods;

 if (methods.join) {

 methods = options.methods.join(&#39;,&#39;); // .methods is an array, so turn it into a string

 }

 return {

 key: &#39;Access-Control-Allow-Methods&#39;,

 value: methods

 };

 }

 

 function configureCredentials(options) {

 if (options.credentials === true) {

 return {

 key: &#39;Access-Control-Allow-Credentials&#39;,

 value: &#39;true&#39;

 };

 }

 return null;

 }

 

 function configureAllowedHeaders(options, req) {

 var allowedHeaders = options.allowedHeaders || options.headers;

 var headers = [];

 

 if (!allowedHeaders) {

 allowedHeaders = req.headers[&#39;access-control-request-headers&#39;]; // .headers wasn&#39;t specified, so reflect the request headers

 headers.push([{

 key: &#39;Vary&#39;,

 value: &#39;Access-Control-Request-Headers&#39;

 }]);

 } else if (allowedHeaders.join) {

 allowedHeaders = allowedHeaders.join(&#39;,&#39;); // .headers is an array, so turn it into a string

 }

 if (allowedHeaders && allowedHeaders.length) {

 headers.push([{

 key: &#39;Access-Control-Allow-Headers&#39;,

 value: allowedHeaders

 }]);

 }

 

 return headers;

 }

 

 function configureExposedHeaders(options) {

 var headers = options.exposedHeaders;

 if (!headers) {

 return null;

 } else if (headers.join) {

 headers = headers.join(&#39;,&#39;); // .headers is an array, so turn it into a string

 }

 if (headers && headers.length) {

 return {

 key: &#39;Access-Control-Expose-Headers&#39;,

 value: headers

 };

 }

 return null;

 }

 

 function configureMaxAge(options) {

 var maxAge = options.maxAge && options.maxAge.toString();

 if (maxAge && maxAge.length) {

 return {

 key: &#39;Access-Control-Max-Age&#39;,

 value: maxAge

 };

 }

 return null;

 }

 

 function applyHeaders(headers, res) {

 for (var i = 0, n = headers.length; i < n; i++) {

 var header = headers[i];

 if (header) {

 if (Array.isArray(header)) {

  applyHeaders(header, res);

 } else if (header.key === &#39;Vary&#39; && header.value) {

  vary(res, header.value);

 } else if (header.value) {

  res.setHeader(header.key, header.value);

 }

 }

 }

 }

 

 function cors(options, req, res, next) {

 var headers = [],

 method = req.method && req.method.toUpperCase && req.method.toUpperCase();

 

 if (method === &#39;OPTIONS&#39;) {

 // preflight

 headers.push(configureOrigin(options, req));

 headers.push(configureCredentials(options, req));

 headers.push(configureMethods(options, req));

 headers.push(configureAllowedHeaders(options, req));

 headers.push(configureMaxAge(options, req));

 headers.push(configureExposedHeaders(options, req));

 applyHeaders(headers, res);

 

 if (options.preflightContinue ) {

 next();

 } else {

 res.statusCode = options.optionsSuccessStatus || defaults.optionsSuccessStatus;

 res.end();

 }

 } else {

 // actual response

 headers.push(configureOrigin(options, req));

 headers.push(configureCredentials(options, req));

 headers.push(configureExposedHeaders(options, req));

 applyHeaders(headers, res);

 next();

 }

 }

 

 function middlewareWrapper(o) {

 if (typeof o !== &#39;function&#39;) {

 o = assign({}, defaults, o);

 }

 

 // if options are static (either via defaults or custom options passed in), wrap in a function

 var optionsCallback = null;

 if (typeof o === &#39;function&#39;) {

 optionsCallback = o;

 } else {

 optionsCallback = function (req, cb) {

 cb(null, o);

 };

 }

 

 return function corsMiddleware(req, res, next) {

 optionsCallback(req, function (err, options) {

 if (err) {

  next(err);

 } else {

  var originCallback = null;

  if (options.origin && typeof options.origin === &#39;function&#39;) {

  originCallback = options.origin;

  } else if (options.origin) {

  originCallback = function (origin, cb) {

  cb(null, options.origin);

  };

  }

 

  if (originCallback) {

  originCallback(req.headers.origin, function (err2, origin) {

  if (err2 || !origin) {

  next(err2);

  } else {

  var corsOptions = Object.create(options);

  corsOptions.origin = origin;

  cors(corsOptions, req, res, next);

  }

  });

  } else {

  next();

  }

 }

 });

 };

 }

 

 // can pass either an options hash, an options delegate, or nothing

 module.exports = middlewareWrapper;

 

}());</strong>

ログイン後にコピー

実装原則は次のとおりです:

Access-Control-Allow-Origin 属性 複数のドメイン名を設定できないことが明らかになったので、このパスは諦める必要があります。

最も一般的で効果的な方法は、リクエストされたヘッダーの Origin 属性値 (req.header.origin) がドメイン名のホワイトリストに含まれているかどうかをサーバー側で判断することです。ホワイトリストに含まれている場合は、Access-Control-Allow-Origin を現在の Origin 値に設定します。これにより、Access-Control-Allow-Origin の単一ドメイン名の要件が満たされ、現在のリクエストがアクセスされることが保証されます。ホワイトリストにない場合は、

エラー メッセージ

が返されます。 このようにして、クロスドメインリクエストの検証をブラウザからサーバーに転送します。 Origin 文字列の検証は、通常の文字列の検証と同等になります。

配列

リストの検証だけでなく、通常のマッチングも使用できます。

具体的なコードは次のとおりです:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

<strong>// 判断origin是否在域名白名单列表中

function isOriginAllowed(origin, allowedOrigin) {

 if (_.isArray(allowedOrigin)) {

 for(let i = 0; i < allowedOrigin.length; i++) {

  if(isOriginAllowed(origin, allowedOrigin[i])) {

  return true;

  }

 }

 return false;

 } else if (_.isString(allowedOrigin)) {

 return origin === allowedOrigin;

 } else if (allowedOrigin instanceof RegExp) {

 return allowedOrigin.test(origin);

 } else {

 return !!allowedOrigin;

 }

}

 

 

const ALLOW_ORIGIN = [ // 域名白名单

 &#39;*.233.666.com&#39;,

 &#39;hello.world.com&#39;,

 &#39;hello..*.com&#39;

];

 

app.post(&#39;a/b&#39;, function (req, res, next) {

 let reqOrigin = req.headers.origin; // request响应头的origin属性

 

 // 判断请求是否在域名白名单内

 if(isOriginAllowed(reqOrigin, ALLOW_ORIGIN)) {

 // 设置CORS为请求的Origin值

 res.header("Access-Control-Allow-Origin", reqOrigin);

 res.header(&#39;Access-Control-Allow-Credentials&#39;, &#39;true&#39;);

 

 // 你的业务代码逻辑代码 ...

 // ...

 } else {

 res.send({ code: -2, msg: &#39;非法请求&#39; });

 }

});</strong>

ログイン後にコピー
そうそう、完璧ですね~

まとめ

以上がCORS クロスドメイン リクエストでマルチドメイン名のホワイトリストを設定するための Node.js のサンプル コード共有の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Node V8 エンジンのメモリと GC の詳細な図による説明 Node V8 エンジンのメモリと GC の詳細な図による説明 Mar 29, 2023 pm 06:02 PM

この記事では、NodeJS V8 エンジンのメモリとガベージ コレクター (GC) について詳しく説明します。

Nodeのメモリ制御に関する記事 Nodeのメモリ制御に関する記事 Apr 26, 2023 pm 05:37 PM

ノンブロッキングおよびイベント駆動に基づいて構築されたノード サービスには、メモリ消費量が少ないという利点があり、大量のネットワーク リクエストの処理に非常に適しています。大量のリクエストを前提として、「メモリ制御」に関する問題を考慮する必要があります。 1. V8 のガベージ コレクション メカニズムとメモリ制限 Js はガベージ コレクション マシンによって制御されます

最適な Node.js Docker イメージを選択する方法について話しましょう。 最適な Node.js Docker イメージを選択する方法について話しましょう。 Dec 13, 2022 pm 08:00 PM

ノード用の Docker イメージの選択は些細なことのように思えるかもしれませんが、イメージのサイズと潜在的な脆弱性は、CI/CD プロセスとセキュリティに大きな影響を与える可能性があります。では、最適な Node.js Docker イメージを選択するにはどうすればよいでしょうか?

Node.js 19 が正式リリースされました。その 6 つの主要な機能についてお話しましょう。 Node.js 19 が正式リリースされました。その 6 つの主要な機能についてお話しましょう。 Nov 16, 2022 pm 08:34 PM

Node 19 が正式リリースされましたので、この記事では Node.js 19 の 6 つの主要な機能について詳しく説明します。

pkg を使用して Node.js プロジェクトを実行可能ファイルにパッケージ化する方法について説明します。 pkg を使用して Node.js プロジェクトを実行可能ファイルにパッケージ化する方法について説明します。 Dec 02, 2022 pm 09:06 PM

Nodejs実行可能ファイルをpkgでパッケージ化するにはどうすればよいですか?次の記事では、pkg を使用して Node プロジェクトを実行可能ファイルにパッケージ化する方法を紹介します。

Node の File モジュールについて詳しく説明しましょう Node の File モジュールについて詳しく説明しましょう Apr 24, 2023 pm 05:49 PM

ファイル モジュールは、ファイルの読み取り/書き込み/開く/閉じる/削除の追加など、基礎となるファイル操作をカプセル化したものです。ファイル モジュールの最大の特徴は、すべてのメソッドが **同期** と ** の 2 つのバージョンを提供することです。 asynchronous**、sync サフィックスが付いているメソッドはすべて同期メソッドであり、持たないメソッドはすべて異種メソッドです。

Nodeのイベントループについて話しましょう Nodeのイベントループについて話しましょう Apr 11, 2023 pm 07:08 PM

イベント ループは Node.js の基本的な部分であり、メイン スレッドがブロックされていないことを確認することで非同期プログラミングが可能になります。イベント ループを理解することは、効率的なアプリケーションを構築するために重要です。次の記事では、Node のイベント ループについて詳しく説明します。お役に立てれば幸いです。

ノードがnpmコマンドを使用できない場合はどうすればよいですか? ノードがnpmコマンドを使用できない場合はどうすればよいですか? Feb 08, 2023 am 10:09 AM

ノードが npm コマンドを使用できない理由は、環境変数が正しく設定されていないためです。解決策は次のとおりです: 1. 「システムのプロパティ」を開きます; 2. 「環境変数」->「システム変数」を見つけて、環境を編集します。変数; 3.nodejs フォルダーの場所を見つけます; 4.「OK」をクリックします。

See all articles