티스토리 뷰

tomcat에서 jndi datasource 설정을 하는 방법은 전에 알아보았다. 

 

 

Tomcat JNDI Datasource 설정하여 Spring 연동하기

보통은 로컬 개발환경을 제외하고는 was에 datasource 설정을 하는 JNDI 방식을 많이 사용을 한다. JNDI는 datasource 설정을 was에서 하고 효율적인 connection pool 관리 등 여러가지 장점을 가지고 있어서 주

oingdaddy.tistory.com

위 글에서 간략하게 암호화 하는 과정에 대해서 알아보았는데 오늘은 이것을 구체적으로 알아보도록 하겠다. 

 

암호화하는 역할을 하는 프로젝트를 jar로 추출한다고 했었는데 이 암호화하는 역할을 하는 DataSourceFactory를 가지고 있는 프로젝트는 다음을 참고했다. 세상엔 참 뛰어난 사람들이 많다. 

 

 

Encrypting passwords in Tomcat – JDev

Apache Tomcat is by far the most popular (open source) web server and Java servlet container. It has been around for a long time and – at the time of writing this post – has reached version 7.0.29. As Apache rightfully claims on its web site, Tomcat p

www.jdev.it

이곳에서 EncryptedDataSourceFactory.java와 Encryptor.java 클래스를 가지고 와서 EncryptModule 이라는 프로젝트를 간단하게 하나 만들었다. 

 

클래스의 내용은 위 링크에도 있지만 간략하게 알아보면 (유심히 볼 필요는 없다. 어차피 packing할거라..)

 

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) {
        	System.out.println("Error instantiating decryption class." + 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.setUsername(encryptor.decrypt(poolProperties.getUsername()));
        poolProperties.setPassword(encryptor.decrypt(poolProperties.getPassword()));

        // 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;
    }

}

 

tomcat의 DataSourceFactory 클래스를 상속받아 만든 클래스로 <Resource> 의 factory 부분에 해당하는 클래스이다. 이 클래스의 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 = "asdfo23jda3sds";

	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 testid = "testid";
		System.out.println("Id:" + aes.encrypt(testid));

		String testpassword = "testpassword";
		System.out.println("Pw:" + aes.encrypt(testpassword));
	}
}

 

여기서 유심히 봐야할곳은 main 메소드이다. 이곳에서 db 접속을 위한 username과 password에 해당하는 정보를 입력 후 main 메소드를 실행해 encrypt 시키고 이 값을 잘 보관해 둔다. 

 

 

그 다음은 이 프로젝트를 jar로 export를 시켜준다. 과정은 다음과 같다. 

 

프로젝트 우클릭 > Exprot > jar 입력 > JAR file > 추출할 jar 파일명 입력 후 Finish

 

이렇게 하면 jar 파일이 생성이 되었을것이고 이 jar 파일을 톰캣설치경로/lib 밑에 넣어둔다. 이렇게 생성한 jar 파일 외에 commons-collections.jar, commons-dbcp.jar, commons-pool.jar 파일들도 추가적으로 넣어준다. 

 

 

이렇게 한다음에 server.xml이나 context.xml 파일에 

<Context>
...
  <Resource name="jndi/test" auth="Container"
        factory="secured.EncryptedDataSourceFactory"
        type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
        url="jdbc:oracle:thin:@ip:port:sid"
        username="암호화된id" password="암호화된pwd" maxTotal="20" maxIdle="20"
        maxWaitMillis="-1"/>
</Context>

이곳의 password 부분에 아까 Encryptor.java 를 통해 생성한 암호화된id암호화된pwd 를 넣어준다. 또한 EncryptedDataSourceFactory 클래스의 full path도 factory 부에 기입을 한다. 

 

이렇게 하면 tomcat의 username/password 암호화에 대한 설정은 끝이 난다. 

 

댓글
최근에 올라온 글
최근에 달린 댓글
«   2024/04   »
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