CSRF跨站请求伪装
CSRF也叫作XSRF,这是一项用来获取未认证站点私有数据的一种技术。vert.x-web模块包含CSRFHandler处理器,你可以使用它阻止伪装的请求。
对于每个请求,CSRFHandler会将一个唯一个的token添加到响应头。客户端再请求时会将此token设置在请求头返回给服务器。因此需要发送需要的cookie并且cookie处理器必须放在路由之前。
当开发非单一页面应用时,主要依赖User-Agent头去执行Post动作。请求头不能在HTML表单中指定。为了解决这相问题,请求头的值 和表单属性都必须被检查,有时会在表单中设置与头相同名字的表单字段值。
<form action="/submit" method="POST">
<input type="hidden" name="X-XSRF-TOKEN" value="abracadabra">
</form>
用户有责任为表单字段填写正确的值。喜欢使用纯HTML解决方案的用户可以通过从路由上下文中获取密钥X-XSRF-token下的令牌值或在CSRFHandler对象实例化期间选择的头名称来填充该值
router.route().handler(CSRFHandler.create(vertx, "abracadabra"));
router.route().handler(ctx -> {
});
注意:CSRFHandler是session感知的。如果从session可以得到token值 ,在Post请求中表单参数或者头值可能被或略,因为CSRFHandler会从session中获取。这就在session升级时会隐式重新产生token.
注意,为了获得额外的安全性,建议用户旋转标记令牌的密钥。这可以通过替换处理程序或使用新配置重新启动应用程序来在线完成。点击劫持仍然会影响应用程序。如果这是一个关键应用程序,请考虑设置标题:X-Frame-Options,如所述:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
使用AJAX
当使用ajax访问保护URL时,CSRFtoken需要通过请求传入。通常,这是使用请求头来完成的,因为添加请求头通常可以在中心位置(可以统一处理)轻松完成,而无需修改负载。
CSRF token可以在上下文中的使用X-XSRF-Token 名字的KEY获取。这个token需要暴露给客户端。通常被包含在初始页面内容中。一种可能是保存在HTML meta标签中。因为token值在使用javaScript进行请求时可以使用到。
下面可以包含在你的页面中
<meta name="csrf-token" content="${X-XSRF-TOKEN}">
下面是使用Fetch API post请求/process url,并通过<meta>标签携带CSRF token的例子
// Read the CSRF token from the <meta> tag
var token = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
// Make a request using the Fetch API
fetch('/process', {
credentials: 'same-origin', // <-- includes cookies in the request
headers: {
'X-XSRF-TOKEN': token // <-- is the csrf token as a header
},
method: 'POST',
body: {
key: 'value'
}
})
HSTS 处理器
HTTP 严格传输安全是一个web安全机制,此机制保护站点被中间人攻击,如协议降级和cookie劫持。HSTS容话web服务器向浏览器声明(一些合规的用户代理,这里指浏览器),应该自动仅使用HTTPS连接进行交互。HSTS提供了传输层 安全(TLS/SSL),与单独使用的不安全HTTP不同。HSTS是IETF标准跟踪协义并且也是RFC6797标准。
下面是只需要一步就可以通过HSTSHandler配置正确的响应头。
router.route().handler(HSTSHandler.create());
CSPHandler 内 容安全策略处理器
内容安全策略处理器被添加到安全层,输助发现和减轻特定的攻击类型。包括Cross Site Scripting (XSS)和数据注入攻击。这些攻击被用于从数据盗窃到网站污损再到恶意软件的分发。
CSP设计为完全向后兼容。不支持CSP的浏览器仍然可以与实现CSP的服务器一起工作,反之亦然:不支持CSP浏览器只是忽略它,照常运行,默认为web内容的标准同源策略。如果站点不提供CSP标头,浏览器同样使用标准的同源策略。
router.route().handler(
CSPHandler.create()
.addDirective("default-src", "*.trusted.com"));
XFrameHandler
X-Frame-Options HTTP响应标头可用于指示是否允许浏览器在框架、iframe、嵌入或对象中呈现页面。网站可以通过确保其内容不嵌入其他网站来避免点击劫持攻击。
仅当访问文档的用户使用支持X-Frame-Options的浏览器时,才提供附加的安全性。
如果指定DENY,则从其他站点加载页面时,在框架中加载页面的尝试不仅会失败,而且从同一站点加载时,这样做的尝试也会失败。另一方面,如果指定SAMEORIGIN,则仍然可以在框架中使用页面,只要框架中包含该页面的站点与提供该页面的网站相同。
此处理程序将在一个步骤中为应用程序配置正确的标头:
router.route().handler(XFrameHandler.create(XFrameHandler.DENY));
OAuth2AuthHandler Handler
OAuth2AuthHandler允许使用OAuth2协议快速设置安全路由。此处理程序简化了authCode流。使用它来保护某些资源并通过GitHub进行身份验证的示例可以实现为:
OAuth2Auth authProvider = GithubAuth
.create(vertx, "CLIENT_ID", "CLIENT_SECRET");
// create a oauth2 handler on our running server
// the second argument is the full url to the
// callback as you entered in your provider management console.
OAuth2AuthHandler oauth2 = OAuth2AuthHandler
.create(vertx, authProvider, "https://myserver.com/callback");
// setup the callback handler for receiving the GitHub callback
oauth2.setupCallback(router.route("/callback"));
// protect everything under /protected
router.route("/protected/*").handler(oauth2);
// mount some handler under the protected zone
router
.route("/protected/somepage")
.handler(ctx -> ctx.response().end("Welcome to the protected resource!"));
// welcome page
router
.get("/")
.handler(ctx -> ctx.response()
.putHeader("content-type", "text/html")
.end("Hello<br><a href=\"/protected/somepage\">Protected by Github</a>"));
OAuth2AuthHandler将设置正确的回调OAuth2处理程序,因此用户不需要处理授权服务器响应的验证。非常重要的是,要知道授权服务器响应只有效一次,这意味着如果客户端发出回调URL的重新加载,它将被断言为无效请求,因为验证将失败。
经验法则是,一旦执行了有效的回调,就会发出客户端重定向到受保护的资源。此重定向还应创建会话cookie(或其他会话机制),这样用户就不需要对每个请求进行身份验证。
由于OAuth2规范的性质,为了使用其他OAuth2提供程序,需要进行一些细微的更改,但vertx-auth为您提供了许多开箱即用的实现:
-
Azure Active Directory
AzureADAuth
-
Box.com
BoxAuth
-
Dropbox
DropboxAuth
-
Facebook
FacebookAuth
-
Foursquare
FoursquareAuth
-
Github
GithubAuth
-
Google
GoogleAuth
-
Instagram
InstagramAuth
-
Keycloak
KeycloakAuth
-
LinkedIn
LinkedInAuth
-
Mailchimp
MailchimpAuth
-
Salesforce
SalesforceAuth
-
Shopify
ShopifyAuth
-
Soundcloud
SoundcloudAuth
-
Stripe
StripeAuth
-
Twitter
TwitterAuth
然而,如果你正在使用一个不在上面列表中的认证,你可以使用基本的api实现
OAuth2Auth authProvider = OAuth2Auth.create(vertx, new OAuth2Options()
.setClientId("CLIENT_ID")
.setClientSecret("CLIENT_SECRET")
.setSite("https://accounts.google.com")
.setTokenPath("https://www.googleapis.com/oauth2/v3/token")
.setAuthorizationPath("/o/oauth2/auth"));
// create a oauth2 handler on our domain: "http://localhost:8080"
OAuth2AuthHandler oauth2 = OAuth2AuthHandler
.create(vertx, authProvider, "http://localhost:8080");
// these are the scopes
oauth2.withScope("profile");
// setup the callback handler for receiving the Google callback
oauth2.setupCallback(router.get("/callback"));
// protect everything under /protected
router.route("/protected/*").handler(oauth2);
// mount some handler under the protected zone
router
.route("/protected/somepage")
.handler(ctx -> ctx.response().end("Welcome to the protected resource!"));
// welcome page
router
.get("/")
.handler(ctx -> ctx.response()
.putHeader("content-type", "text/html")
.end("Hello<br><a href=\"/protected/somepage\">Protected by Google</a>"));
你需要手动提供所有的细节,但是最终结果是相同的。
处理程序将为您的应用程序固定配置的回调url。用法很简单,只要为处理程序提供一个路由实例,所有设置都将为您完成。在一个典型的用例中,您的提供者会问您应用程序的回调url是什么,然后输入一个url,如:
https://myserver.com/callback。这是处理程序的第二个参数,现在您只需要设置它。为了使最终用户更容易,您只需调用setupCallback方法。
这就是将处理程序固定到服务器的方式
https://myserver.com:8447/callback。
请注意,默认值不必输入端口号,http为80,https为443
OAuth2AuthHandler oauth2 = OAuth2AuthHandler
.create(vertx, provider, "https://myserver.com:8447/callback");
// now allow the handler to setup the callback url for you
oauth2.setupCallback(router.route("/callback"));
在本例中,路由对象由Router内联创建。route()但是,如果您想完全控制调用处理程序的顺序(例如,您希望在链中尽快调用它),您可以始终在之前创建route对象,并将其作为对此方法的引用传递。