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. 使用日志记录错误信息,但避免泄露敏感信息。
相关推荐
Dnelic-3 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen5 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年12 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿15 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神16 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛16 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法17 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
NotesChapter18 小时前
Android吸顶效果,并有着ViewPager左右切换
android
_祝你今天愉快19 小时前
分析android :The binary version of its metadata is 1.8.0, expected version is 1.5.
android
暮志未晚Webgl19 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5