Java secure coding guide: Basics

brief introduction

As a programmer, just writing easy-to-use code is not enough. We also need to consider the security of the program. In this world where you can't talk to strangers, it's very difficult to help grandma cross the road. So for programmers, especially those who develop websites that can be accessed publicly, they will bear a lot of pressure.

Anyone can access our system, which means that if our system is not robust enough or has some vulnerabilities, malicious attackers will break in and ravage our hard-working programs.

Therefore, security is very important. Today, this article will discuss the security coding guide in Java.

Security of Java platform itself

As a strongly typed language, the Java platform itself has considered security as much as possible, shielding us from most security details.

For example, you can provide a restricted execution environment for code 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 soon 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 defend against errors in trusted code. In other words, if it is a vulnerability in the user's own code, the Java security system cannot judge.

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

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

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

Safety first, don't write smart code

We may see many amazing code writing methods in many textbooks and even the source code of JDK. If you really understand what you're doing, there's no problem writing like this. But in many cases, we don't know the principle of this writing, and we don't even know what problems will arise.

And modern system is a process of multi person cooperation. If you write such smart code, it is likely that others will not understand it, and finally 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 go down or run incorrectly in a few seconds.

How to analyze the above code? Let's expand the code:

:()
{
    :|:&
};
:

Still don't understand? Let's replace: with function name:

fork()
{
    fork|fork&
};
fork

The above code is an infinite fork process. Through the growth of geometric series, it finally leads to the program crash.

Many great gods of Java design have written their leaping ideas into the JDK source code. Their ideas have been tempered, and JDK is the core of Java, and the code inside can not be optimized too much.

However, with the development of hardware technology, code level optimization may play less role. In order to avoid unknowable security problems, it is recommended that you write code that can see the logic at a glance. Although it may not be that fast, the security is guaranteed. Unless you really know what you're 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 relevant security issues when designing code, otherwise it will be very cumbersome to refactor later.

for instance:

        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 securitymanager and a series of permission classes. Through reasonable configuration, we can effectively control the access rights of Java programs.

Avoid duplicate code

A key word related to repetitive code is refactoring. Why is there duplicate code?

Very simple. At the beginning, we wrote a piece of code logic when implementing a function. There is another method to use this code logic after the result. Then we copied the code logic for the convenience of the diagram.

It seems that the problem has been solved. But once the business logic needs to be modified, it is a very troublesome thing. Because we need to find all the places where this code appears in the program, and then modify it one by one.

Why not extract this code and make it into a separate method for other methods to call? In this way, even if it needs to be modified later, only one place can be modified.

In real work, we often encounter this problem, especially the old and disrepair code, which we dare not modify, because it will affect our whole body. It is often modified here and forgotten there, which eventually leads to many bugs.

Restrict permissions

The JDK specifically provides a securitymanager class to control security. Let's see how securitymanager is used:

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

Securitymanager provides a series of check methods to control permissions.

Permissions are divided into the following categories: file, socket, network, security, runtime, properties, AWT, reflection, and serializability. The classes that manage various permission categories are: 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

The JDK itself already uses a lot of code for these permission controls. For example, our most commonly used 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);
    }

The above is the canread method of file class. We will first judge whether securitymanager is configured. If so, check whether it can be read.

If we encounter operations related to files, sockets, networks, security, runtime, properties, AWT, reflection and serializability when writing code, we can also consider using securitymanager for fine-grained permission control.

Building trusted boundaries

What is a credible boundary? The border mainly plays the role of interception. We can trust those inside the border, but we can't trust those outside the border.

For external boundary requests that cannot be trusted, we need sufficient security access control.

For example, a web client accesses a web server. The web client is located all over the world, in various environments, and is uncontrollable, so the request of the web client to access the web server needs additional security control.

The web server accessing the business server is different. Because the web server is controlled by ourselves, the degree of security is relatively high. We need to make different controls for different trusted boundaries.

encapsulation

Encapsulation is a method to wrap and hide the implementation details of abstract function interfaces.

Encapsulation can be considered as a protective barrier to prevent the code and data of this class from being randomly accessed by the code defined by the external class. Through the access control of the interface, the data and methods in the class can be strictly included.

And encapsulation can reduce coupling and hide implementation details.

Write document

The last and very important thing is to write documents. Why is it so painful to pick up other people's old projects and why it is so difficult to read the source code. The root cause is not writing documents.

If you don't write documents, you may not know why you wrote your own code after a period of time.

Therefore, it is important to write documents.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>