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. 使用日志记录错误信息,但避免泄露敏感信息。
相关推荐
白雪落青衣33 分钟前
buuoj course 1详细解析
android
恋猫de小郭1 小时前
Android 发布全新性能分析器,实用性和性能大升级
android·前端·flutter
Kapaseker1 小时前
为什么 Java 的数组需要 new 出来
android·java·kotlin
黄林晴1 小时前
颠覆开发!Google AI Studio 一句话生成原生 Android App
android·google io
恋猫de小郭1 小时前
Flutter 3.44 发布啦,超级大版本更新!!!
android·flutter·ios
zb200641202 小时前
Laravel10.x重磅升级:新特性全解析
android
2601_957418802 小时前
深入解析Android相机有线连接:PTP与MTP协议栈实现原理与实践
android·数码相机·智能手机
努力努力再努力wz2 小时前
【QT入门系列】QWidget 六大常用属性详解:windowOpacity、cursor、font、focus、toolTip 与 styleSheet
android·开发语言·数据结构·c++·qt·mysql·算法
撩得Android一次心动2 小时前
C语言基础笔记3【个人用】
android·c语言·开发语言·笔记
小离a_a2 小时前
uniapp小程序封装圆环显示比例数据
android·小程序·uni-app