반응형
0. 상황
Vue.js에서 아이디(userId)와 비밀번호(userPassword)를 입력하여 로그인을 해봅니다.
개발자 모드(F12)를 켜서 페이로드를 살펴보면 다음과 같이 사용자가 입력한 아이디와 비밀번호를 바로 확인할 수 있습니다.
보안을 위해 비밀번호(userPassword)를 암호화하여 요청하고 싶습니다. 이때 우리는 바로 전 포스팅에서 생성한 비대칭 키 RSA를 사용할 것입니다.
1. Vue.js에서 RSA 공개키로 암호화
JavaScript 라이브러리인 jsencrypt를 사용하여 암호화를 수행할 것입니다. 이를 위해 먼저 jsencrypt를 설치해줍니다.
npm install jsencrypt
그런 다음, Vue.js 컴포넌트에서 RSA 공개키로 암호화를 수행하는 코드를 작성합니다.
저는 해당 코드를 전역으로 사용하기 위해 main.js에 작성하였습니다.
function encryptData(data, publicKey) {
var encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey);
return encryptor.encrypt(data).toString();
}
Vue.prototype.$encryptData = encryptData;
해당 코드를 통해 원래 평문으로 보내졌던 비밀번호가 다음과 같이 암호화됨을 확인할 수 있습니다.
2. Spring Boot에서 RSA 개인키로 복호화
RSA 공개키로 암호화된 비밀번호를 서버에서 받으면 RSA 개인키로 복호화 해주어야 합니다.
전 생성한 private_key_pkcs8.pem 파일을 resources 디렉토리 밑에 두었습니다. 예제 볼때 참고!!
@Value("${rsa.private-key.filename}")
private String privateKeyFile;
public String decryptData(String encryptedData) {
try {
// RSA 개인키의 문자열
Resource privateKeyResource = new ClassPathResource(privateKeyFile);
String privateKeyContent = new BufferedReader(new InputStreamReader(privateKeyResource.getInputStream()))
.lines().collect(Collectors.joining("\n"))
privateKeyContent = privateKeyContent
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
// RSA 개인키를 PrivateKey 객체로 변환
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyContent);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// 암호문을 바이트 배열로 변환하고 복호화
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
byte[] decryptedBytes = decryptEncryptedBytes(encryptedBytes, privateKey);
// 복호화된 데이터 문자열로 변환
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
throw new SSMAuthException(ErrorCode.FAIL_DECRYPT_DATA, e.getMessage());
}
}
// 복호화를 위한 Cipher 객체 초기화
private byte[] decryptEncryptedBytes(byte[] data, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
- 헤더와 푸터(-----BEGIN PRIVATE KEY-----, -----END PRIVATE KEY-----)를 삭제해주었습니다.
- 정규식에서 \s는 공백 문자를 나타냅니다. 공백 문자는 스페이스, 탭, 개행 등을 포함합니다. \s+을 매칭함으로 한 개 이상의 공백 문자들을 빈 문자열("")로 바꿔주었습니다. 위에 개행("\n")으로 문자열을 이어준 것이 의미가 없지만, 파일에 있는 private_key_pkcs8.pem 파일에 담긴 문자열을 그대로 가져와 확인하기 위해 작성해보았습니다.
지금까지 RSA 암호화를 통해 요청 시 데이터의 보안을 고려하는 방법을 살펴보았습니다. 각각의 데이터들을 암호화하거나, 객체를 통째로 암호화하거나, 각 데이터들을 암호화하여 하나의 필드에 두는 등 여러 방법을 고려하여 도입해봐야겠습니다.
반응형
'Web' 카테고리의 다른 글
OpenSSL을 통해 RSA 공개키, 개인키 생성하기 (0) | 2024.03.12 |
---|---|
웹 보안을 위한 XSS, CSRF 방어 (1) | 2023.11.13 |
CORS(Cross-Origin Resource Sharing) 이해와 해결 방법 (0) | 2023.09.18 |
웹 데이터 저장: 로컬 스토리지, 세션 스토리지, 쿠키 (0) | 2023.09.18 |
Jar와 War의 차이(spring initializr packaging) (0) | 2023.09.01 |