Java Encryption and Security Defense: 20 Best Practices from National Secret Algorithms to Defending Against SQL Injection

At three in the morning, I was staring at the abnormal login records suddenly appearing on the production environment monitoring screen— a test account attempted to log in with a password 300 times within 5 minutes. This reminded me of a data breach incident I personally experienced three years ago: an e-commerce system used MD5 to store passwords without salting, resulting in the leakage of 600,000 user data. That painful lesson forced me to embark on a path of “forced upgrades” in the field of encryption and security.

1. National Secret Algorithm: When the SM Series Meets Bouncy Castle

Last year, while doing localization for a government system, the client required the use of the SM4 encryption algorithm. As a newcomer to national secret algorithms, I got lost in the ocean of JCE:

// Typical mistake: directly calling Cipher.getInstance("SM4").
public static byte[] sm4Encrypt(byte[] key, byte[] iv, byte[] data) {
    Security.addProvider(new BouncyCastleProvider()); // Must add BC provider
    Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS7Padding", "BC");
    //... subsequent operations are similar to AES
}

Avoid Pitfalls Guide: The national secret algorithm requires the support of Bouncy Castle, just like coffee needs a companion. Remember to include it in your pom.xml:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15to18</artifactId>
    <version>1.69</version>
</dependency>

In practice, I found an interesting phenomenon: the collision rate of the SM3 hash algorithm (the domestic version of SHA-256) is three orders of magnitude lower than that of MD5, but remember to calculate in segments when processing long texts:

MessageDigest md = MessageDigest.getInstance("SM3", "BC");
md.update("Government System".getBytes(StandardCharsets.UTF_8));
md.update("Sensitive Data".getBytes(StandardCharsets.UTF_8));
byte[] digest = md.digest(); // This is the correct approach

2. SQL Injection Defense: The Precompiled “Spear and Shield”

During a code audit, I found this piece of “divine logic”:

String sql = "SELECT * FROM users WHERE id=" + request.getParameter("id");
// A newcomer confidently said: "I used PreparedStatement!"
PreparedStatement stmt = connection.prepareStatement(sql); 

Fatal Misunderstanding: The essence of precompilation is to let the SQL engine understand the structure of the command first. If you directly concatenate user input into the SQL statement and then hand it over to the precompiled interface, it’s like putting poison in a coffee cup— it looks safe, but it’s actually deadly.

The real defense posture should be:

// Correct approach: parameterized query
PreparedStatement stmt = connection.prepareStatement(
    "SELECT * FROM users WHERE id=? AND status=?");
stmt.setInt(1, Integer.parseInt(userInputId)); // Convert type first
stmt.setString(2, "active");

But the story doesn’t end here—I once saw such an “advanced attack” in a financial system:

WHERE username LIKE '%' + ? + '%'

The attacker input<span>_a%</span> (the underscore is a wildcard), successfully bypassing the fuzzy query restrictions. The solution is to escape the parameters:

String keyword = "user_input".replace("!", "!!")
                             .replace("%", "!%")
                             .replace("_", "!_");

3. 20 Security Principles Earned Through Blood and Tears

  1. Three Principles of Password Storage: PBKDF2 iteration count ≥ 10,000 + independent salt for each user + mandatory use of SHA-256 or SM3
  2. HTTPS Against Man-in-the-Middle Attacks: Use HSTS headers to enforce encrypted transmission, and don’t be lazy with certificate fingerprint verification
  3. Double Insurance for Input Validation: Frontend format prompts, backend use regex whitelists (e.g., phone number validation:<span>^1[3-9]\d{9}$</span>)
  4. MyBatis Against Injection: Absolutely do not use<span>${}</span>, XML mapping’s<span>#{}</span> is the true child
  5. Log Security Traps: Prohibit recording full credit card numbers, use<span>logger.debug("Payment processed: {}****{}", cardFirst4, cardLast4)</span>
  6. CSRF Defense: Spring Security’s<span>SameSite=Strict</span> + custom token double verification
  7. XXE Protection: Disable external entity parsing <span>DocumentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);</span>
  8. Deserialization Vulnerabilities: Use<span>ObjectInputFilter</span> to configure whitelists, as strict as customs security checks
  9. Druid Connection Pool: Enable firewall filtering for<span>DELETE FROM</span> and other dangerous operations
  10. JWT Security: Enforce signature algorithm verification, don’t believe<span>alg:none</span> nonsense

(Due to space limitations, please follow my GitHub repository for the complete 20 items)

4. The Cat-and-Mouse Game of Security Offense and Defense

Last year, while testing an API interface with Burp Suite, I found that the response header contained<span>X-Powered-By: Spring Boot</span>, exposing the technology stack. It’s like holding a sign saying “I am here” on the battlefield. The solution is simple:

@Configuration
public class SecurityHeaderConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaults().disable(); // Disable default headers
    }
}

But the true art of offense and defense lies in the balance between attack and defense. I once used the JEP290 mechanism to defend against deserialization attacks, but the attacker switched to memory horse injection. At this point, we need to deploy Java Agent for runtime monitoring—security is a dynamic process, just like getting vaccinated requires regular boosters.

Finally, Questions for Your Reflection

Suppose you are now to design a financial-grade permission system:

  1. How to implement a dual-review mechanism for sensitive operations?
  2. When the national secret algorithm meets distributed sessions, how should the keys be managed?
  3. How to use Java Instrumentation technology to achieve runtime SQL injection detection?

(The answers may exist in the Security module of my open-source project, but I recommend you practice first. Remember: what you learn from books is shallow; true understanding comes from practice—especially when your system is breached by the Red Team, this experience will be particularly profound.)

Leave a Comment