일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 브라우저
- User-Agent
- WINDOW11
- 접근장치
- Oracle
- JEUS
- Was
- programmers
- scheduled
- Firebase
- web server
- dbms
- Tomcat
- FCM
- URLRewirte
- window10
- 개발자도구
- mysql
- TailMe
- 물리적주소
- 알고리즘
- WebtoB
- ua-parser
- @Scheduled
- Login
- db
- eGov
- 암호화
- AES
- Java
- Today
- Total
HD
Tomcat Server.xml 암호화 (feat.AES) 본문
프로젝트 중에 Server.xml DB Resource 부분에 url, id, password 암호화를 할수없냐는 문의가 들어와서 찾아 보고 적용을 해보았다.
암호화하는 역할을 하는 DataSourceFactory를 가지고 참조해 소스를 수정 및 추가를 하였다.
작업한 소스는 총2개이다 Encryptor.java, EncryptedDataSourceFactory.java
※EncryptedDataSourceFactory의 full path 기억하기
[Encryptor.java]
package secured;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class Encryptor {
private static final String ALGORITHM = "AES";
private static final String defaultSecretKey = "SecretKeyTest";//AES secretKey
private Key secretKeySpec;
public Encryptor() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException,
UnsupportedEncodingException {
this(null);
}
public Encryptor(String secretKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
UnsupportedEncodingException {
this.secretKeySpec = generateKey(secretKey);
}
public String encrypt(String plainText) throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
return asHexString(encrypted);
}
public String decrypt(String encryptedString) throws InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] original = cipher.doFinal(toByteArray(encryptedString));
return new String(original);
}
private Key generateKey(String secretKey) throws UnsupportedEncodingException, NoSuchAlgorithmException {
if (secretKey == null) {
secretKey = defaultSecretKey;
}
byte[] key = (secretKey).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only the first 128 bit
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
return new SecretKeySpec(key, ALGORITHM);
}
private final String asHexString(byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
private final byte[] toByteArray(String hexString) {
int arrLength = hexString.length() >> 1;
byte buf[] = new byte[arrLength];
for (int ii = 0; ii < arrLength; ii++) {
int index = ii << 1;
String l_digit = hexString.substring(index, index + 2);
buf[ii] = (byte) Integer.parseInt(l_digit, 16);
}
return buf;
}
public static void main(String[] args) throws Exception {
Encryptor aes = new Encryptor(defaultSecretKey);
String url ="jdbc:mysql://127.0.0.1:3306/testDb?characterEncoding=UTF-8";
System.out.println("url:" + aes.encrypt(url));
String testid = "test";
System.out.println("Id:" + aes.encrypt(testid));
String testpassword = "test";
System.out.println("Pw:" + aes.encrypt(testpassword));
}
}
[EncryptedDataSourceFactory.java]
package secured;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.Properties;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.naming.Context;
import javax.sql.DataSource;
import org.apache.tomcat.jdbc.pool.DataSourceFactory;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.XADataSource;
public class EncryptedDataSourceFactory extends DataSourceFactory {
private Encryptor encryptor = null;
public EncryptedDataSourceFactory() {
try {
encryptor = new Encryptor(); // If you've used your own secret key, pass it in...
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@Override
public DataSource createDataSource(Properties properties, Context context, boolean XA) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, SQLException, NoSuchAlgorithmException,
NoSuchPaddingException {
// Here we decrypt our password.
PoolConfiguration poolProperties = EncryptedDataSourceFactory.parsePoolProperties(properties);
poolProperties.setUrl(encryptor.decrypt(poolProperties.getUrl())); //dbConUrl 복호화
poolProperties.setUsername(encryptor.decrypt(poolProperties.getUsername())); //username복호화
poolProperties.setPassword(encryptor.decrypt(poolProperties.getPassword())); //password복호화
/*
setValidationQuery Option
SELECT 1(mysql), SELECT 1 FROM DUAL(oracle), SELECT 1(mssql)
*/
poolProperties.setValidationQuery("SELECT 1");
poolProperties.setTestWhileIdle(true);
poolProperties.setTimeBetweenEvictionRunsMillis(720000);//2시간 단위로 SELECT 1 검증
// The rest of the code is copied from Tomcat's DataSourceFactory.
if (poolProperties.getDataSourceJNDI() != null && poolProperties.getDataSource() == null) {
performJNDILookup(context, poolProperties);
}
org.apache.tomcat.jdbc.pool.DataSource dataSource = XA ? new XADataSource(poolProperties)
: new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
dataSource.createPool();
return dataSource;
}
}
[Encryptor.java bulid]
server.xml에 암호화한 값들을 넣어주기위해 Encryptor.java를 먼저 컴파일해서 값을 확인해본다.
[jar 추출]
(순서) - Export -> java에 JAR file -> JAR file에 경로와 jar파일명 설정후 Finish (하단 이미지 참조)
[Server.xml 설정]
Resource 부분에 factory="com.github.tomcatEncryptModule.EncryptedDataSourceFactory"를 추가해준다.
<Resource auth="Container"
factory="com.github.tomcatEncryptModule.EncryptedDataSourceFactory" #여기가 중요
driverClassName="com.mysql.jdbc.Driver"
maxActive="50"
maxIdle="10"
maxWait="-1"
name="jdbc/testDB"
password="암호화값"
type="javax.sql.DataSource"
url="암호화값"
username="암호화값"/>
서버 재기동후 정상으로 작동되는지 확인!!
[적용후 개인생각]
만약 이걸 각 프로젝트마다 defaultSecretKey가 바뀐다 생각을 하면 소스 수정후 jar로 묶는 작업이 번거로울수 있다보니 해당 지정된 properties파일을 생성해서 properties에 defaultSecretKey관리 변수를 추가후 관리 해주는 방안도 있을거 같다.
//예시
//AES secretKey
private static final String defaultSecretKey = properties.getProperty("SecretKey");
[jar 파일]
[git url]
https://github.com/hunecenter94/tomcat-jdbc-encrypt-module
[참조]
http://www.jdev.it/encrypting-passwords-in-tomcat/
https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/tomcat/jdbc/pool/DataSourceFactory.html
'WAS > Tomcat' 카테고리의 다른 글
리눅스 톰켓 한글 깨짐 현상 해결 (0) | 2022.03.08 |
---|---|
session clustering 적용 (feat.Tomcat7 이상) (0) | 2020.10.05 |
TOMCAT 버전업 문제 (0) | 2020.08.04 |
Tomcat JDK변경 (0) | 2020.07.13 |
Tomcat ORACLE JNDI Datasource 설정 (0) | 2019.01.23 |