保护应用程序的十种方法

Ťhis blog post is adapted from a talk given by Joe Kutner at Devoxx 2018 titled "10 Mistakes Hackers Want You to Make."

不再需要构建自卫的应用程序和服务,这是必需的。 现在,应用安全补丁,正确处理密码,清理输入并正确编码输出是摆在桌面上的重担。 我们的攻击者不断进步,我们也必须如此。

In this blog post, we'll take a look at several commonly overlooked ways to secure your web apps. Many of the examples provided will be specific to Java, but any modern programming language will have equivalent tactics. Please feel free to share methods for other languages in the comments.

1. Ensure dependencies are up-to-date

Every year, OWASP, a group of security experts and researchers, publishes a list of the common application security risks to watch out for. One of the more common issues they've found is the use of dependencies with known vulnerabilities. Once a known CVË is published, many open source maintainers and contributors make a concentrated effort to released patched updates to popular frameworks and libraries. But one report found that more than 70% of exploited applications are due to outdated dependencies.

为确保您的项目依赖最新和最好的软件包,并且自动化您的依赖管理被推荐。

With Maven, you can use the Maven Versions Plugin, which automatically updates your pom.xml to use the newest packages. In Ruby, the bundle update command does something similar. You could incorporate these tools into your CI/CD process, and have a test outright fail if a dependency is outdated, thus forcing you to upgrade a package before your app can be deployed.

A more proactive approach might be to incorporate a tool that automatically monitors your dependencies for you, such as Snyk. Rather than running a check when code is modified (which could expose your app to a vulnerability for weeks or months, if it's infrequently updated), Snyk monitors your dependencies and compares them with a known list of vulnerabilities mapped to dependencies. If a problem is identified, they'll alert you with a report identifying which dependencies are outdated and which version contains a patched fix. Snyk is also free to try on Heroku.

2. Explicitly declare acceptable user payloads

All too often, web applications will accept nearly anything a user submits through a form or an API. For example, a user may attempt to create an account with a password containing over a thousand characters. When numerous requests like this are sent, it is possible the server will crash under the intense computation necessary to encrypt them.

减轻此类攻击的一种方法是实现数据库级别的约束。 列应定义为最大大小,否则您的数据模型应拒绝接受空值价值观。 尽管将这些限制放在数据库上始终是一个好主意,但是由于某些攻击可以在请求周期的较早时间内被公平利用,因此可以将其视为“低级”。

If your application is exposed to the Internet, every vulnerability is just one curl call away. 一世n one example with the Jackson data-binding library, a simple JSON payload was able to execute arbitrary code, once the request was received by the server.

By providing an explicit list of expected inputs , you can ensure that your application is only operating on data that it knows will be coming, and ignoring (or politely erroring) on everything else. If your application accepts JSON, perhaps as part of an API, implementing JSON schemas are an excellent way to model acceptable requests. For example, if an endpoint takes two string fields named firstName and lastName, and one integer named age, a JSON schema to validate user-provided requests might look like this:

{
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 1
    }
  }
}

通过声明有效的类型,可以防止如果用户决定为以下类型发送整数,则可以防止出现意外问题:名字或负数年龄。

除了请求正文之外,您还应该检查请求标头和查询参数,它们可以被类似地利用。

3. Assert safe regular expressions

正则表达式对每个开发人员都是福音和诅咒。 它们可以使字符串上的模式匹配变得容易,但是设计不当的正则表达式也会使应用程序崩溃。

Consider a simple pattern like this one: (a|aa)+. While it looks innocuous, the | ("or") combined with the + operator can take a catastrophically long time to match against a string such as "aaaaaaaaaaaaaaaaaaaaaaaa!". Malicious users could cause a denial-of-service attack on your system by submitting a particularly complicated (yet still technically "valid") text. (A similar issue affected the Node.js community several years ago.)

Validating your regular expressions will ensure that they are not susceptible to this type of ReDoS attack. One tool you can use is saferegex, a command-line Java utility that will report on the likelihood of a regular expressions causing a problem:

$ java -jar target/saferegex.jar "(a|aa)+"

Testing: (a|aa)+
More than 10000 samples found.
***
This expression is vulnerable.
Sample input: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab

4. Prevent abusive requests

构建流行的应用程序不仅仅涉及添加所需的功能。 您的网站还需要处理随着其增长而收到的流量。 即使您的应用程序的每个部分都是安全的,反复攻击您的服务器的不良行为者也可能成功将其关闭。

为了确保用户的正常运行时间,您应该限制积极的客户。 这可以通过几种不同的方式完成,例如通过IP地址或用户代理限制请求。

A better implementation would be to use a library that takes advantage of a token-bucket algorithm. Bucket4j is one such library. Incoming requests are grouped by a variety of properties into individual "buckets," and those buckets can in turn be throttled or blacklisted entirely. By classifying which requests are acceptable and which aren't, you'll be able to better handle sudden bursts of traffic.

5. Align your code to be secure-first

通常,在一个特别令人沮丧的错误中,我们可能会急于实施从Internet某个角落偷来的解决方案。 而最后解决问题可能是急需的解决方案,因此始终值得进行三重检查,以确保您没有无意中引入了安全问题。

A few years ago, researchers found that a majority of acceptable answers on StackOverflow contained insecure flaws. Code that works does not mean that code is secure. Even if a snippet works in the short-term, it's important to be absolutely certain that it is safe to use.

6. Store credentials outside your codebase

我们都知道(希望如此!)泄露您的个人密码可能是灾难性的错误。 在任何足够复杂的应用程序中,可以管理许多不同的令牌和密码:您的数据库用户名和密码,用于向New Relic或DataDog或Redis进行身份验证的令牌...

将应用程序的配置与代码分开。即使您的存储库是私有的,嵌入明文凭据也不是一个好主意。 不该拥有访问权限的不满员工可能会窃取令牌以冒充用户。 为了确保您的项目安全,您应该确信,如果代码在任何时候都成为开源代码,则不会破坏您的凭据。

Store your secrets in environment variables. A library like dotenv can seamlessly load and make use of these variables, provided they're accessible in a secure location. Another option is to use a product like Hashicorp Vault, which allows your application to manage secrets through a configurable CLI.

7. Deny HTTP requests

Unless you have a very specific use case, you should disable HTTP connections to your server. An HTTPS connection ensures that data between the client and the server is encrypted, thus prohibiting person-in-the-middle snooping attacks. Most major browsers default to HTTPS connections by default, and services such as Let's Encrypt make it easier than ever to obtain an SSL certificate for your application.

If you need to support HTTP locally or between a proxy and your web server, you can configure your server to only accepts clients whose X-Forwarded-Proto request header is set to https. Depending on your setup, this may also be configurable outside of your code via an NGINX or Apache configuration.

8. Enable certificate checking

有时,您的应用程序可能需要致电外部提供商。 与以上建议类似,您应该对出站连接启用证书检查。 这确保了通过HTTPS也可以保护与第三方API或服务的通信。 请注意,如果第三方网站的证书配置错误,则在您的应用程序尝试连接时可能会导致错误。 您可能会尝试禁用证书检查以确保应用程序“正常运行”,但这是一个非常不安全的举动,使您的用户数据处于危险之中。

You can use a library like EnvKeyStore to facilitate the storage of keys and certificates. Similar to dotenv, EnvKeyStore asks that you keep set a certificate PEM be to an environment variable. You can then use this PEM as the default checker for any outgoing client requests. For example:

KeyStore ts = EnvKeyStore.createWithRandomPassword("TRUSTED_CERT").keyStore();

String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(ts);

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, tmf.getTrustManagers(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

String urlStr = "https://ssl.selfsignedwebsite.xyz";
URL url = new URL(urlStr);
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.setDoInput(true);
con.setRequestMethod("GET");
con.getInputStream().close();

9. Log and monitor suspicious behavior

许多应用程序仅记录严重故障,例如意外的服务器错误。 但是,即使我们已经解释了行为,也可以用作攻击媒介。 在这种情况下,必须记录任何敏感动作。 要记录的某些行为的示例包括:

  • 成功和失败的登录重设密码更改访问级别授权失败

在许多情况下,反复产生错误的用户可能是恶意攻击者试图接管帐户的迹象。

为了将这些事件与其他错误区分开,我们建议您在日志语句前加上诸如以下的短语SECURITY_SUCCESS,SECURITY_FAILURE,and SECURITY_AUDIT. This way,you can easily filter on specific categories of authorization failures,should the need arise. Keep in mind that sensitive information,such as session IDs or passwords,should not be logged,as they will be stored in plaintext.

Another tactic to employ is to add an intrusion detection system. OWASP has a project called 一种ppSensor, which provides a framework to detect and respond to potential attacks in an automated way. This works by adding an agent to your web application which sends events to your external AppSensor service. AppSensor will analyze those events, and, if it determines malicious behavior, AppSensor will respond back to the web app with a payload of information identifying what is going on. The application can then determine which action to take.

UML of AppSensor

Take a look at the list of AppSensor detection points to potentially identify where your application needs improved intrusion detection.

10. Limit your own access

我们都会犯错。 尽管我们要求应用程序的用户在行为时考虑到安全性,我们还需要练习良好的安全卫生。 每个人都应采取的一些常识性措施包括:

  • 尽可能使用两因素身份验证不在办公室时随时锁定计算机屏幕在帐户和服务之间实施唯一密码,并使用密码管理器

Final thoughts

安全是困难的,不是因为难以实现,而是因为难以识别怎么样是安全的。 在编写代码时,要实现预期的功能要容易得多,而构想意外的功能要困难得多,因为这会引起安全问题。 此外,还有许多种健康状况良好的安全性:网络安全性,平台安全性,物理安全性等。

The ten ways you just learned to protect yourself are good starting points to ensure that your application security is top-notch. If you want to continue learning about web application security, you can check out the OWASP Getting Started guide for more information.

请保持安全,并再次分享您在注释中使用的所有安全提示-适用于Java或任何其他语言!

from: https://dev.to//heroku/ten-ways-to-secure-your-applications-48df

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值