此文只是对vert.x Web应用程序的入门指导(大神请绕道)。 这绝不是对Web应用程序安全性的全面指导,如OWASP。 标准规则和惯例适用于vert.x应用程序。
不要用root身份运行
DEVOPS团队成员会经常说,只给必要的运行权限,不要多给。有些新手试图以root用户在80或443端口下运行,虽然这样简单,但也为坏蛋打开一扇门。 让我们看看下面的代码:
public class App extends AbstractVerticle {
@Override
public void start() {
Router router = Router.router(vertx);
router.route().handler(StaticHandler.create(""));
vertx.createHttpServer().requestHandler(router::accept).listen(80);
}
}
|
当与开始CWD
设置为/
(java -Dvertx.cwd=/ ...
)你就创建了一个简单的文件服务器,给所有服务器存储。 现在,假设你要启动这个程序,会打印如下错误:
Aug 26, 2015 2:02:18 PM io.vertx.core.http.impl.HttpServerImpl
SEVERE: java.net.SocketException: Permission denied
|
如果你现在使用root
运行的,浏览器输入http://localhost/etc/shadow
,恭喜你,你的服务器logins
和 passwords
暴露了 !
有几种方法,可以root用户运行,使用iptables
请求转发到更高的端口,使用authbind
,配置代理服务器ngnix
等…
Sessions
许多应用程序要处理在某些时候用户会话。
会话Cookie
应该有SECURE
和HTTPOnly
设置的标志,只发送HTTPS
(在使用HTTPS
?),也没有脚本访问cookie
的客户端:
Router router = Router.router(vertx);
router.route().handler(CookieHandler.create());
router.route().handler(SessionHandler
.create(LocalSessionStore.create(vertx))
.setCookieHttpOnlyFlag(true)
.setCookieSecureFlag(true)
);
router.route().handler(routingContext -> {
Session session = routingContext.session();
Integer cnt = session.get("hitcount");
cnt = (cnt == null ? 0 : cnt) + 1;
session.put("hitcount", cnt);
routingContext.response().end("Hitcount: " + cnt);
});
vertx.createHttpServer().requestHandler(router::accept).listen(8080);
|
在这种情况下,检查浏览器,应该看到:
你的浏览器的脚本有读取的能力,可以嗅探劫持或篡改您的会话。
Security Headers
有很多的安全headers
有助于提高安全性,只需几行代码。 没有必要在这里解释,因为网上有很好的文章说的做得可能会比我更好。
怎么实现:
public class App extends AbstractVerticle {
@Override
public void start() {
Router router = Router.router(vertx);
router.route().handler(ctx -> {
ctx.response()
// do not allow proxies to cache the data
.putHeader("Cache-Control", "no-store, no-cache")
// prevents Internet Explorer from MIME - sniffing a
// response away from the declared content-type
.putHeader("X-Content-Type-Options", "nosniff")
// Strict HTTPS (for about ~6Months)
.putHeader("Strict-Transport-Security", "max-age=" + 15768000)
// IE8+ do not allow opening of attachments in the context of this resource
.putHeader("X-Download-Options", "noopen")
// enable XSS for IE
.putHeader("X-XSS-Protection", "1; mode=block")
// deny frames
.putHeader("X-FRAME-OPTIONS", "DENY");
});
vertx.createHttpServer().requestHandler(router::accept).listen(8080);
}
}
|
保护跨站请求伪造(CSRF)
Vert.x web
在handler
里提供了CSRF
保护。下面代码增加CSRF保护:
public class App extends AbstractVerticle {
@Override
public void start() {
Router router = Router.router(vertx);
router.route().handler(CookieHandler.create());
router.route().handler(SessionHandler
.create(LocalSessionStore.create(vertx))
.setCookieHttpOnlyFlag(true)
.setCookieSecureFlag(true)
);
router.route().handler(CSRFHandler.create("not a good secret"));
router.route().handler(ctx -> {
...
});
|
该处理器(handler)增加了一个CSRF令牌(token)。 为了改变cookie
(XSRF-TOKEN),设置了一个独一无二的token
,即预计返回一个(X-XSRF-TOKEN)header。
限制上传
上传处理一定要定义一个上限,否则你会很容易受到DDoS攻击。 例如,看看下面的代码:
public class App extends AbstractVerticle {
@Override
public void start() {
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
router.route().handler(ctx -> {
...
|
现在,“好心人”可以随机生成一个1GB的垃圾文件:
dd if=/dev/urandom of=ddos bs=1G count=1
|
然后把它上传到你的服务器:
curl --data-binary "@ddos" -H "Content-Type: application/octet-stream" -X POST http://localhost:8080/
|
您的应用程序将愉快地处理,上面两步不断重复,它会耗尽磁盘空间或内存。 为了减轻这些类型的攻击,始终指定的最大允许上传的大小:
public class App extends AbstractVerticle {
private static final int KB = 1024;
private static final int MB = 1024 * KB;
@Override
public void start() {
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create().setBodyLimit(50 * MB));
|
最后
虽然只有几点,也应该记住。
当程序要用于生产,你还要注意更多: