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. 使用日志记录错误信息,但避免泄露敏感信息。
相关推荐
雨白6 分钟前
实现双向滑动的 ScalableImageView(下)
android
峥嵘life13 分钟前
Android Studio新版本编译release版本apk实现
android·ide·android studio
studyForMokey3 小时前
【Android 消息机制】Handler
android
敲代码的鱼哇3 小时前
跳转原生系统设置插件 支持安卓/iOS/鸿蒙UTS组件
android·ios·harmonyos
翻滚丷大头鱼3 小时前
android View详解—动画
android
我是好小孩3 小时前
[Android]RecycleView的item用法
android
胖虎13 小时前
Android Studio 读取本地文件(以 ZIP 为例)
android·ide·android studio·本地文件·读取本地文件
出海小纸条3 小时前
Google Play 跨应用脚本漏洞(Cross-App Scripting)
android
小孔龙3 小时前
Android Runtime(ART) GC 日志手册
android
袁美丽..3 小时前
Android --- SystemUI 导入Android Studio及debug
android·ide·android studio