Java Security Coding Guide: The Basics

As a programmer, it is not enough to write useful code. We also need to consider the security of the program. In this world where you can't talk to strangers, helping an old woman to cross the road is very difficult. So for programmers, especially for programmers who develop websites that are publicly accessible to the outside world, the pressure will be much greater.

Anyone can access our system, which means that if our system is not robust enough, or if there are some loopholes, malicious hackers will break in and ravage our hard-wrote programs.

Therefore, security is very important. Today this article will discuss the secure coding guidelines in java.

The security of the java platform itself

As a strongly typed language, the java platform itself has taken security into consideration as much as possible, shielding us from most security details.

For example, a restricted execution environment can be provided for codes with different levels of permissions. Java programs are type-safe, and provide automatic memory management and array boundary checking at runtime. Java will find problems in the program as early as possible, so that Java programs have a high ability to resist stack destruction.

Although the Java security architecture can help protect users and systems from malicious code or improper behavior in many cases, it cannot protect against errors that occur in trusted code. In other words, if it is a loophole in the user's own code, the java security system cannot be judged.

These errors may bypass Java's own security architecture. In severe cases, local programs may be executed or Java security may be disabled. It can be used to steal confidential data from computers and Intranets, abuse system resources, prevent useful operations of computers, assist in further attacks, and many other malicious activities.

Therefore, the greatest security lies in the programmer. No matter how powerful the external mechanism is, if the core programmer has a problem, then everything will fall into nothingness.

Next, let's take a look at what code of conduct Java programmers should follow to ensure the safety of the program?

Safety first, don't write smart code

We may see a lot of amazing code writing in many textbooks and even the source code of JDK. If you really understand what you are doing, then there is no problem writing this way. But in many cases, we don't really understand the principle of writing this way, or even what kind of problems will arise when writing this way.

And the modern system is a process of multi-person collaboration. If you write such smart code, it is very likely that others will not be able to understand it, which will eventually lead to unknown system problems.

Let me give you an example:

:(){:|:&};:

The above is a fork bomb under the shell. If you run the above code under the shell, the system will crash or run errors after a few seconds.

How to analyze the above code? We expand the code:

:()
{    :|:&};:

Still do not understand? We replace: with the function name:

fork()
{    fork|fork&
};fork

The above code is an infinite fork process, which eventually leads to a program crash through geometric growth.

Many great gods of java design have written their leap-like thoughts into the JDK source code. The thoughts of the great gods have been tempered, and JDK is the core of Java, and the code inside cannot be optimized.

However, with the development of hardware technology, code-level optimization may have less effect. In order to avoid unknowable security issues, it is recommended that you write code that can see the logic at a glance. Although it may not be so fast, but safety is guaranteed. Unless you really know what you are doing.

Consider security at the beginning of code design

Security should be a very important standard in the process of writing code. We should consider related security issues when designing the code, otherwise it will be very troublesome to refactor later.

for example:

        public final class SensitiveClass {

            private final Behavior behavior;            // Hide constructor.
            private SensitiveClass(Behavior behavior) {                this.behavior = behavior;
            }            // Guarded construction.
            public static SensitiveClass newSensitiveClass(Behavior behavior) {                // ... validate any arguments ...

                // ... perform security checks ...

                return new SensitiveClass(behavior);
            }
        }

In the above example, we used the final keyword to prevent some of our key classes from being inherited and extended. Because there is no scalability, security judgment will be easier.

At the same time, java provides a SecurityManager and a series of Permission classes. Through reasonable configuration, we can effectively control the access permissions of java programs.

Avoid duplicate code

A key word associated with repetitive code is refactoring. Why is there duplicate code?

It's very simple. At the beginning, we wrote a piece of code logic when we implemented a function. After the result, there is a way to use this code logic. Then we copied the code logic for the convenience of the diagram.

看起来问题好像解决了。但是一旦这段业务逻辑要修改,那可就是非常麻烦的一件事情。因为我们需要找到程序中所有出现这段代码的地方,然后一个一个的修改。

为什么不把这段代码提取出来,做成一个单独的方法来供其他的方法调用呢?这样即使后面需要修改,也只用修改一处地方即可。

在现实的工作中,我们经常会遇到这种问题,尤其是那种年久失修的代码,大家都不敢修改,因为牵一发而动全身。往往是修改了这边忘记了那边,最后导致bug重重。

限制权限

JDK专门提供了一个SecurityManager类,来显示的对安全性进行控制,我们看下SecurityManager是怎么使用的:

SecurityManager security = System.getSecurityManager();
    if (security != null) {
      security.checkXXX(argument, ...);
   }

SecurityManager提供了一系列的check方法,来对权限进行控制。

权限分为以下类别:文件、套接字、网络、安全性、运行时、属性、AWT、反射和可序列化。管理各种权限类别的类是 :
  java.io.FilePermission、
  java.net.SocketPermission、
  java.net.NetPermission、
  java.security.SecurityPermission、
  java.lang.RuntimePermission、
  java.util.PropertyPermission、
  java.awt.AWTPermission、
  java.lang.reflect.ReflectPermission
  java.io.SerializablePermission

JDK本身已经使用了很多这些权限控制的代码。比如说我们最常用的File:

    public boolean canRead() {
        SecurityManager security = System.getSecurityManager();        if (security != null) {
            security.checkRead(path);
        }        if (isInvalid()) {            return false;
        }        return fs.checkAccess(this, FileSystem.ACCESS_READ);
    }

上面是File类的canRead方法,我们会首先去判断是否配置了SecurityManager,如果配置了,则去检查是否可以read。

如果我们在写代码中,遇到文件、套接字、网络、安全性、运行时、属性、AWT、反射和可序列化相关的操作时,也可以考虑使用SecurityManager来进行细粒度的权限控制。

构建可信边界

什么是可信边界呢?边界主要起拦截作用,边界里边的我们可以信任,边界外边的我们就不能信任了。

对于不能信任的外边界请求,我们需要进行足够的安全访问控制。

比如说web客户端来访问web服务器。web客户端是在全球各地的,各种环境都有,并且是不可控的,所以web客户端访问web服务器端的请求需要进行额外的安全控制。

而web服务器访问业务服务器又是不同的,因为web服务器是我们自己控制的,所以安全程度相对较高,我们需要针对不同的可信边界做不同的控制。

封装

封装(Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。

封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。通过对接口进行访问控制,可以严格的包含类中的数据和方法。

并且封装可以减少耦合,并且隐藏实现细节。

写文档

最后一项也是非常非常重要的一项就是写文档。为什么接别人的老项目那么痛苦,为什么读源代码那么困难。根本的原因就是没有写文档。

如果不写文档,可能你自己写的代码过一段时间之后也不知道为什么当时这样写了。

所以,写文档很重要。

【免责声明:本文图片及文字信息均由千锋重庆Java培训小编转载自网络,旨在分享提供阅读,版权归原作者所有,如有侵权请联系我们进行删除。】

Guess you like

Origin blog.51cto.com/15128443/2667955