CleanCode、安全编码规范

Clean Code 规范

Clean Code 是由 Robert C. Martin 提出的编写高质量代码的原则。主要包括以下几点

有意义的命名

  • 命名要准确和清晰,让人一看就知道变量、函数或类的用途。
  • 避免使用缩写和难以理解的名称
Kotlin 复制代码
// 不好的命名
val d: Int = 5

// 好的命名
val daysUntilDeadline: Int = 5

函数要短小精悍

  • 一个函数只做一件事
  • 函数尽量短小,易于理解和测试。
Kotlin 复制代码
// 不好的例子
fun processUserData(user: User) {
    validateUser(user)
    saveUserToDatabase(user)
    sendWelcomeEmail(user)
}

// 好的例子
fun validateUser(user: User) { /* ... */ }
fun saveUserToDatabase(user: User) { /* ... */ }
fun sendWelcomeEmail(user: User) { /* ... */ }

减少嵌套层次

  • 使用早期返回来减少不必要的嵌套
Kotlin 复制代码
// 不好的例子
fun isValidUser(user: User): Boolean {
    if (user != null) {
        if (user.isActive) {
            if (user.hasPermission) {
                return true
            }
        }
    }
    return false
}

// 好的例子
fun isValidUser(user: User?): Boolean {
    if (user == null) return false
    if (!user.isActive) return false
    if (!user.hasPermission) return false
    return true
}

注释要有意义

  • 仅在必要时添加注释,代码本身应该是最好的文档。
  • 避免无意义的注释。
Kotlin 复制代码
// 不好的例子
// 这个函数返回用户的年龄
fun getUserAge(user: User): Int {
    return user.age
}

// 好的例子
// Only add comments if the code isn't clear enough by itself

安全编码规范

安全编码规范旨在防止常见的安全漏洞,提高代码的安全性。以下是一些关键原则:

  1. 输入验证

    • 确保所有外部输入都经过验证和清理,防止注入攻击。
Kotlin 复制代码
fun validateInput(input: String): Boolean {
    val pattern = Regex("^[a-zA-Z0-9_]+$")
    return input.matches(pattern)
}

避免硬编码敏感信息

  • 不要在代码中硬编码密码、密钥等敏感信息。使用安全的存储机制,如 Android 的 Keystore
Kotlin 复制代码
// 不好的例子
val apiKey = "12345"

// 好的例子
val apiKey = getApiKeyFromSecureStorage()

使用安全的库和算法

  • 使用经过验证的安全库和加密算法,避免自己实现加密算法。
Kotlin 复制代码
// 不好的例子
fun encrypt(data: String): String {
    // custom encryption logic
}

// 好的例子
fun encrypt(data: String): ByteArray {
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
    return cipher.doFinal(data.toByteArray())
}

避免泄露敏感信息

  • 在日志中避免打印敏感信息,如用户数据、密码等。
Kotlin 复制代码
// 不好的例子
Log.d("UserData", "Password: $password")

// 好的例子
Log.d("UserData", "Password entered")

最小权限原则

  • 仅授予程序执行其任务所需的最小权限,避免使用不必要的权限。
Kotlin 复制代码
<!-- 不好的例子 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.INTERNET"/>

<!-- 好的例子 -->
<uses-permission android:name="android.permission.INTERNET"/>

错误处理

  • 处理所有异常,避免程序崩溃,并给用户友好的提示。
  • 不要暴露内部实现细节。
Kotlin 复制代码
// 不好的例子
fun readFile(filename: String): String {
    return File(filename).readText()
}

// 好的例子
fun readFile(filename: String): String {
    return try {
        File(filename).readText()
    } catch (e: IOException) {
        Log.e("FileRead", "Error reading file", e)
        "Error reading file"
    }
}

真实的例子和方案代码

结合 Clean Code 和安全编码规范,以下是一个例子:

示例:用户登录
Kotlin 复制代码
import android.content.Context
import android.util.Log
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore

class LoginManager(context: Context) {
    private val keyAlias = "LoginKeyAlias"
    private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
    private val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    private val preferences = context.getSharedPreferences("login_prefs", Context.MODE_PRIVATE)

    init {
        if (!keyStore.containsAlias(keyAlias)) {
            val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
            keyGenerator.init(KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build())
            keyGenerator.generateKey()
        }
    }

    private fun getSecretKey(): SecretKey {
        return (keyStore.getEntry(keyAlias, null) as KeyStore.SecretKeyEntry).secretKey
    }

    fun encrypt(data: String): ByteArray {
        cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
        val iv = cipher.iv
        val encryptedData = cipher.doFinal(data.toByteArray())
        preferences.edit().putString("iv", iv.joinToString(",")).apply()
        return encryptedData
    }

    fun decrypt(encryptedData: ByteArray): String {
        val iv = preferences.getString("iv", "")!!.split(",").map { it.toByte() }.toByteArray()
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), GCMParameterSpec(128, iv))
        return String(cipher.doFinal(encryptedData))
    }

    fun login(username: String, password: String): Boolean {
        if (!validateInput(username) || !validateInput(password)) {
            Log.e("LoginManager", "Invalid input")
            return false
        }
        val encryptedPassword = encrypt(password)
        // 发送用户名和加密后的密码到服务器进行验证
        return true
    }

    private fun validateInput(input: String): Boolean {
        val pattern = Regex("^[a-zA-Z0-9_]+$")
        return input.matches(pattern)
    }
}

在这个例子中,我们创建了一个 LoginManager 类,遵循了 Clean Code 和安全编码规范,包括:

  1. 使用有意义的命名,如 LoginManagerencryptdecrypt
  2. 函数短小且只做一件事,如 encryptdecrypt
  3. 安全处理用户输入,防止注入攻击。
  4. 使用 Android Keystore 存储和管理加密密钥,确保敏感信息安全。
  5. 使用日志记录错误信息,但避免泄露敏感信息。
相关推荐
NoSi EFUL8 小时前
MySQL中ON DUPLICATE KEY UPDATE的介绍与使用、批量更新、存在即更新不存在则插入
android·数据库·mysql
安小牛10 小时前
Android 开发汉字转带声调的拼音
android·java·学习·android studio
聚美智数10 小时前
企业实际控制人查询-公司实控人查询
android·java·javascript
JMchen12311 小时前
第 3 篇|Android 项目结构解析与第一个界面 —— Hello, CSDN!
android·android studio·android 零基础·android 项目结构·android 界面开发
众少成多积小致巨14 小时前
Soong构建入门
android·go·编译器
笔夏14 小时前
【安卓学习之混淆】记录一些混淆导致闪退
android·学习
阿巴斯甜14 小时前
Kotlin高阶函数和Java 8 lambda的区别:
android
张小潇15 小时前
AOSP15 WMS/AMS系统开发 - WindowManagerService relayout调用流程详解
android
阿巴斯甜15 小时前
Kotlin 高阶函数:
android
之歆15 小时前
Day03_HTML 列表、表格、表单完整指南(下)
android·javascript·html