面试题答案
一键面试Kotlin 代码安全
- 防止注入攻击
- SQL 注入:在 Kotlin 中使用 SQL 语句时,避免直接拼接字符串构建 SQL 语句。使用预编译语句,例如在 JDBC 中,使用
PreparedStatement
。例如:
- SQL 注入:在 Kotlin 中使用 SQL 语句时,避免直接拼接字符串构建 SQL 语句。使用预编译语句,例如在 JDBC 中,使用
val sql = "SELECT * FROM users WHERE username =? AND password =?"
val pstmt = connection.prepareStatement(sql)
pstmt.setString(1, username)
pstmt.setString(2, password)
val rs = pstmt.executeQuery()
- **命令注入**:避免直接拼接用户输入来执行系统命令。使用 `ProcessBuilder` 并正确处理参数。例如:
val command = listOf("ls", "-l", userInputPath)
val process = ProcessBuilder(command).start()
- 数据加密
- 对称加密:可以使用
javax.crypto
包中的类。例如,使用 AES 算法:
- 对称加密:可以使用
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
val keyGen: KeyGenerator = KeyGenerator.getInstance("AES")
keyGen.init(256)
val secretKey: SecretKey = keyGen.generateKey()
val cipher: Cipher = Cipher.getInstance("AES")
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
val encrypted = cipher.doFinal(dataToEncrypt)
- **非对称加密**:使用 RSA 算法时,可如下操作:
import java.security.KeyPairGenerator
import java.security.PrivateKey
import java.security.PublicKey
import javax.crypto.Cipher
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
keyPairGenerator.initialize(2048)
val keyPair = keyPairGenerator.generateKeyPair()
val publicKey: PublicKey = keyPair.public
val privateKey: PrivateKey = keyPair.private
val cipher: Cipher = Cipher.getInstance("RSA")
cipher.init(Cipher.ENCRYPT_MODE, publicKey)
val encrypted = cipher.doFinal(dataToEncrypt)
cipher.init(Cipher.DECRYPT_MODE, privateKey)
val decrypted = cipher.doFinal(encrypted)
Docker 镜像安全
- 镜像构建过程中的安全配置
- 使用最小基础镜像:选择官方的最小化基础镜像,如
alpine
而不是完整的操作系统镜像。例如,在Dockerfile
中:
- 使用最小基础镜像:选择官方的最小化基础镜像,如
FROM alpine:latest
- **减少不必要的软件包安装**:仅安装应用运行必需的软件包。在 `alpine` 中,使用 `apk add` 安装必要包时,避免安装多余依赖。例如:
RUN apk add --no-cache openjdk11-jre
- **清理构建缓存**:构建完成后清理缓存,减少镜像体积和潜在安全风险。例如在 `alpine` 中:
RUN apk add --no-cache <package> && \
apk del <package>-dev && \
rm -rf /var/cache/apk/*
- 漏洞扫描
- 使用 Clair 等工具:Clair 是专门用于扫描 Docker 镜像漏洞的工具。可以在 CI/CD 流程中集成 Clair,例如在 GitLab CI 中:
image: docker:latest
stages:
- build
- scan
build:
stage: build
script:
- docker build -t my - app.
scan:
stage: scan
script:
- docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec / clair-scanner:latest scan --ip - allowlist 127.0.0.1 my - app
容器运行时安全
- 权限管理
- 最小权限原则:容器应使用最小权限运行。避免以
root
用户运行容器,而是创建特定用户。例如在Dockerfile
中:
- 最小权限原则:容器应使用最小权限运行。避免以
RUN adduser -D myuser
USER myuser
- **限制容器能力**:仅赋予容器运行所需的内核能力。例如,若容器不需要网络嗅探等高级权限,不要赋予 `CAP_NET_RAW` 能力。在启动容器时:
docker run --cap - drop=ALL --cap - add=NET_BIND_SERVICE my - app
- 网络隔离
- 默认网络隔离:Docker 默认使用桥接网络,每个容器有独立的网络命名空间,相互隔离。若需更细粒度控制,可使用自定义网络。例如创建一个自定义桥接网络:
docker network create my - network
然后将容器连接到该网络:
docker run --network my - network my - app
- **安全组和防火墙**:在宿主机层面,配置安全组和防火墙规则,限制容器对外暴露的端口和访问来源。例如在 Linux 中使用 `iptables` 配置规则,只允许特定 IP 访问容器暴露的端口。
实际应用中可能面临的安全挑战及应对措施
- 供应链攻击
- 挑战:恶意篡改基础镜像或依赖库。例如,攻击者在开源库中植入恶意代码,当应用依赖该库时被攻击。
- 应对措施:使用官方和可信赖的镜像源和依赖库。定期更新依赖,并使用工具如
Dependency - Check
扫描依赖库的漏洞。在构建镜像时,验证镜像和依赖的签名。
- 容器逃逸
- 挑战:攻击者利用容器运行时漏洞,突破容器边界,访问宿主机或其他容器资源。
- 应对措施:保持容器运行时(如 Docker)和内核的及时更新,修复已知漏洞。限制容器对宿主机资源的访问,如通过
--device - cgroup - rules
限制设备访问。
- 数据泄露
- 挑战:容器内数据未加密存储,或在容器间共享数据时未妥善保护,导致数据泄露。
- 应对措施:对容器内敏感数据加密存储,如前文所述的 Kotlin 数据加密方法。在容器间共享数据时,使用安全的存储卷挂载方式,并对存储卷加密。同时,对容器间通信进行加密,例如使用 TLS。