eggjs / egg

🥚 Born to build better enterprise frameworks and apps with Node.js & Koa
https://eggjs.org
MIT License
18.9k stars 1.82k forks source link

CORS,跨域问题,CSRF 的防范的问题。 #2470

Closed roc2539 closed 6 years ago

roc2539 commented 6 years ago

情况是这样的。 前端用的的是antd pro,后端egg。前后端跨域。 前端在.webpackrc.js设置了 proxy,请求后端egg,返回"message": "missing csrf token"。请求thinkjs正常。 然后再egg中设置了 cors config.default.js中设置 config.security = { // xframe: { // enable: false, // }, // csrf: { // // enable: true, // ignoreJSON: false, // 默认为 false,当设置为 true 时,将会放过所有 content-type 为 application/json 的请求 // useSession: true, // 默认为 false,当设置为 true 时,将会把 csrf token 保存到 Session 中 // cookieName: 'csrfToken', // Cookie 中的字段名,默认为 csrfToken // sessionName: 'csrfToken', // Session 中的字段名,默认为 csrfToken // headerName: 'x-csrf-token', // 通过 header 传递 CSRF token 的默认字段为 x-csrf-token // }, // 白名单 domainWhiteList: ['http://localhost:8000'], }; config.cors = { origin:'http://localhost:8000', allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS', domainWhiteList: ['http://localhost:8000'], };

plugin.js,依然有问题。 exports.cors = { enable: true, package: 'egg-cors', }; // exports.security = { // domainWhiteList: [ 'http://localhost:8000' ], // };

最后尝试走crsf,参考 https://eggjs.org/zh-cn/core/security.html#ajax-请求 https://github.com/eggjs/egg-security#using-csrf-when-request-by-ajax 客户端读取到了cookie,然后设置到Header中 Request 返回。 POST /api2/login HTTP/1.1 Host: localhost:8000 Connection: keep-alive Content-Length: 0 accept: application/json Origin: http://localhost:8000 x-csrf-token: D5Usnww2sbu4V-BN9QRrtlfI User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36 content-type: application/json; charset=utf-8 Referer: http://localhost:8000/ Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 Cookie: csrfToken=D5Usnww2sbu4V-BN9QRrtlfI 这种情况下没有问题了。

但是,前后端交互的时候。第一次交互,后端没有写cookie的时候。就还是会出现"message": "missing csrf token"。怎么处理?

另外,如果配置到csrfToken在session中,前端用, const csrfToken = sessionStorage.getItem('csrfToken');获取不到数据。要怎么获取?配置了session的 httpOnly: false,还是不行。

egg-bot commented 6 years ago

Translation of this issue:


CORS, cross-domain issues, CSRF precautions.

This is the case. The front end uses antd pro, the back end egg. Front-end and back-end cross-domain. The front end sets the proxy in .webpackrc.js, requests the backend egg, and returns "message": "missing csrf token". Request thinkjs normal. Then set cors in egg again Set in config.default.js  Config.security = {         // xframe: {         // enable: false,         // },         // csrf: {         // // enable: true,         // ignoreJSON: false, // defaults to false, when set to true, all requests with content-type of application/json will be ignored         // useSession: true, // defaults to false, when set to true, csrf token will be saved to Session         // cookieName: 'csrfToken', // field name in cookie, default is csrfToken         // sessionName: 'csrfToken', // The field name in the Session, the default is csrfToken         // headerName: 'x-csrf-token', // passing the CSRF token's default field via header to x-csrf-token         // },         // whitelist         domainWhiteList: ['http://localhost:8000'],     };     Config.cors = {         Origin:'http://localhost:8000',         allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',         domainWhiteList: ['http://localhost:8000'],     };

Plugin.js, there are still problems. Exports.cors = {     Enable: true,     Package: 'egg-cors', }; // exports.security = { // domainWhiteList: [ 'http://localhost:8000' ], // };

Finally try to walk crsf, reference Https://eggjs.org/en-us/core/security.html#ajax-request Https://github.com/eggjs/egg-security#using-csrf-when-request-by-ajax The client reads the cookie and sets it in the header Request returns. POST /api2/login HTTP/1.1 Host: localhost:8000 Connection: keep-alive Content-Length: 0 Accept: application/json Origin: http://localhost:8000 X-csrf-token: D5Usnww2sbu4V-BN9QRrtlfI User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36 Content-type: application/json; charset=utf-8 Referer: http://localhost:8000/ Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 Cookie: csrfToken=D5Usnww2sbu4V-BN9QRrtlfI There is no problem in this case.

However, when the front-end and back-end interact. The first interaction, when the backend does not write a cookie. It will still appear "message": "missing csrf token". How to deal with?

In addition, if the configuration to csrfToken in the session, the front end, const csrfToken = sessionStorage.getItem ('csrfToken'); access to data. How to get it? Configure the session's httpOnly: false, or not.

roc2539 commented 6 years ago

最后,我目前的解决办法只有, csrf: { ignoreJSON: true, // 默认为 false,当设置为 true 时,将会放过所有 content-type 为 application/json 的请求 },

可以完全解决,可是这样是不是就不安全了,没有了CSRF的校验机制。 然后还没尝试,在生产环境的校验问题。

dead-horse commented 6 years ago

如果是跨域请求,就不要开 CSRF 的校验了。用 referer 来做防范吧

roc2539 commented 6 years ago

https://eggjs.org/zh-cn/basics/controller.html#referrer-校验 ? jsonp 配置? @dead-horse

roc2539 commented 6 years ago

那我现在就是,关闭csrf, srf: { enable: false, },

然后配置了, exports.jsonp = { whiteList: /^http?:\/\/localhost:8000\//, };

目前来说是OK的

750973092 commented 5 years ago

1553070497(1)

那是这样设置吗

750973092 commented 5 years ago

怎么我没有效果呢