스프링

1. POM.XML 파일에 라이브러리를 추가.

 

<!-- 시큐리티 -->
 		<dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>3.2.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>3.2.3.RELEASE</version>
        </dependency>

 

이것이 안되면   버전을 4. 대로 버전을 올려 줘야 한다.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.1.6.RELEASE</version>
</dependency>       
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.1.6.RELEASE</version>
</dependency>

<!-- security -->
<dependency>
        <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-web</artifactId>
        <version>4.0.4.RELEASE</version>
</dependency>
<dependency>
        <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-core</artifactId>
        <version>4.0.4.RELEASE</version>
</dependency>
<dependency>
        <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-config</artifactId>
        <version>4.0.4.RELEASE</version>
</dependency>

 

2. src/main/resource 에  config 폴서들 생성후 config.properties 파일 추가

# spring security password encoder (default: bCryptPasswordEncoder, shaPasswordEncoder, standardPasswordEncoder)
security.password.encoder = bCryptPasswordEncoder
# spring security password encoder: only shaPasswordEncoder value
security.password.sha = 1
security.password.encodeHashAsBase64 = true

 

 

 

 

3. WEB.XML 수정 

!-- 스프링의 환경설정 파일 로딩 -->
	
<!-- /WEB-INF/spring/security-context.xml 추가 -->
<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml
			/WEB-INF/spring/security-context.xml 
		</param-value>
	</context-param>


	<!-- Security filter 추가 -->

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>   
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

 

4.  root-context.xml 에 추가

  <util:properties id="mei" location="classpath:config/config.properties"/>

 

 

5. security-context.xml 파일 추가 

기본 설정 방법은 

링크 주소 

 

여기에서는  암호화 를 위한 빈 주입만 설정 해도 된다.

패키지명을 자신의 프로젝트에 맞게 변경 할것.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
	xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

	<beans:bean id="bCryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
	
	<beans:bean id="shaPasswordEncoder" class="com.java.ex.SHAPasswordEncoder">
		<beans:constructor-arg value="#{mei['security.password.sha']}" />
		<beans:property name="encodeHashAsBase64" value="#{mei['security.password.encodeHashAsBase64']}" />
	</beans:bean>
	
	
	
	<beans:bean id="standardPasswordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"/>
	
	<beans:bean id="passwordEncoder" class="com.java.ex.PasswordEncoding">
		<beans:constructor-arg ref="#{mei['security.password.encoder']}"/>
	</beans:bean>

</beans:beans>

 

 

6. WEB.XML 수정 

<!-- 스프링의 환경설정 파일 로딩 -->
	
<!-- /WEB-INF/spring/security-context.xml 추가 -->
<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml
			/WEB-INF/spring/security-context.xml 
		</param-value>
	</context-param>


	<!-- Security filter 추가 -->

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>   
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
	

 

또는 지금은  암호화만 고려 할 것이므로 

root-context.xml 에서 임포트만 해 줘도 된다.

 

root-context.xml

	
    <util:properties id="mei" location="classpath:config/config.properties"/>
    
    <import resource="appServlet/security-context.xml"/>
    

 

 

7. 파일 2개를 추가 한다.

smiley1

package com.example.wbe04.util.password;

import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author Seok Kyun. Choi. 최석균 (Syaku)
 * @site http://syaku.tistory.com
 * @since 16. 2. 18.
 */
public class SHAPasswordEncoder implements PasswordEncoder {
	private ShaPasswordEncoder shaPasswordEncoder;
	private Object salt = null;

	public SHAPasswordEncoder() {
		shaPasswordEncoder = new ShaPasswordEncoder();
	}

	public SHAPasswordEncoder(int sha) {
		shaPasswordEncoder = new ShaPasswordEncoder(sha);
	}

	public void setEncodeHashAsBase64(boolean encodeHashAsBase64) {
		shaPasswordEncoder.setEncodeHashAsBase64(encodeHashAsBase64);
	}

	public void setSalt(Object salt) {
		this.salt = salt;
	}

	@Override
	public String encode(CharSequence rawPassword) {
		return shaPasswordEncoder.encodePassword(rawPassword.toString(), salt);
	}

	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		return shaPasswordEncoder.isPasswordValid(encodedPassword, rawPassword.toString(), salt);
	}
}


wink2

package com.example.wbe04.util.password;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author Seok Kyun. Choi. 최석균 (Syaku)
 * @site http://syaku.tistory.com
 * @since 16. 2. 18.
 */
public class PasswordEncoding implements PasswordEncoder {
	private PasswordEncoder passwordEncoder;

	public PasswordEncoding() {
		this.passwordEncoder = new BCryptPasswordEncoder();
	}

	public PasswordEncoding(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	@Override
	public String encode(CharSequence rawPassword) {
		return passwordEncoder.encode(rawPassword);
	}

	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		return passwordEncoder.matches(rawPassword, encodedPassword);
	}
}

 

8. 테스트 및 사용

import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.example.wbe04.util.encoder.PasswordEncoding;
import com.example.wbe04.util.encoder.SHAPasswordEncoder;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
public class PasswordTest {

	@Inject
	PasswordEncoding passwordEncoding;
	
	@Test
	public void test2() {
		// 1234 라 할지라도 매번 다른 값으로 랜덤하게 encoding 된다.
		String encode=passwordEncoding.encode("1234");
		// encode 를 DB에 저장 하면 된다.
		
		//값을 비교 하는 것은 matches() 를 사용해서
		//로그인 유저와 DB에 저장된 비번을 비교 해서 true 값 이면 비번이 일치 한다는 것이다.
		
		passwordEncoding.matches("1234", encode);
		
		System.out.println("passwordEncoding.encode(1234)" +encode);
		System.out.println("1234 비교: " + passwordEncoding.matches("1234", encode));
	}
	
	
}

 

 

9. 프로퍼티 설정 및 root-context.xml  설정 및 security-context.xml 필요 없이 객체를 직접 생성 하려면 

아래와 같은 클래스를 만든 후

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

public class EncodPassword {

	private static PasswordEncoding passwordEncoding;
	
	
	//DB 에 변경해서 저장될 암호
	public static String dbSavePassword(String encodePasswod){
			
		PasswordEncoder passwordEncoder =new BCryptPasswordEncoder();;
		passwordEncoding = new PasswordEncoding(passwordEncoder);
		return passwordEncoding.encode(encodePasswod);
	}
	
	
		
	public static PasswordEncoding getPasswordEncoding() {
		return passwordEncoding;
	}
	
	
}

 

다음 과 같이 사용 하면 된다.

 

import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.example.wbe04.util.encoder.EncodPassword;
import com.example.wbe04.util.encoder.PasswordEncoding;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
public class PasswordTest {

	
	
	@Test
	public void passTest() throws Exception{
		
		String dbpass =EncodPassword.dbSavePassword("1234");
		
		System.out.println("DB에 저장 될 암호 ex) 1234: " + dbpass);
		// EncodPassword.dbPassword() 만 호출해서 반환 값만 DB 에 저장하면 된다.
		// 같은 값이 들어가도 반환 된 값은 랜덤하게 출력 된다. 
		
		// 테스트 로그인 할 유저  매치 값 비교하기  true 로 나오면 설정 완료
		System.out.println("값 비교: " + EncodPassword.getPasswordEncoding().matches("1234", dbpass));
		
		
	}
	
	
}

 

 

 

아래 파일은 최석균 개발자가 샘플 test   (참조용)

public class PasswordEncoderTest {

	@Test
	public void test() {
		String password = "1234";
		
	
		// SHA-256 암호화를 사용한다
		SHAPasswordEncoder shaPasswordEncoder = new SHAPasswordEncoder(512);  
		shaPasswordEncoder.setEncodeHashAsBase64(true);
		
		
		PasswordEncoding passwordEncoding = new PasswordEncoding(shaPasswordEncoder);  //
		
		System.out.println("SHA 암호화: " + passwordEncoding.encode(password));
		System.out.println("SHA 비교: " + passwordEncoding.matches(password, passwordEncoding.encode(password)));
        
		
		//BCryptPasswordEncoder  여기서 PasswordEncoding 상속 받았다.  
		//스프링 시큐리티에서 기본적을 사용하는 암호화 방식으로 암호화가 될때마다 새로운 값을 생성한다. 
		//임의적인 값을 추가해서 암호화하지 않아도 된다. (salt 사용하지 않는다.)
		PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		passwordEncoding = new PasswordEncoding(passwordEncoder);

		
		//두번째 암호화 생성 암호 first2
		String first2=passwordEncoding.encode(password);
		
		System.out.println("1. BCrypt 암호화: " + passwordEncoding.encode(password));
		System.out.println("1. BCrypt 비교: " + passwordEncoding.matches(password, passwordEncoding.encode(password)));

		
		// 3번째  다시 BCrypt 암호화 암호 first3  최종적으로 DB  에 저장 될 값 은 first3
		String first3 =passwordEncoding.encode(first2);
		
		System.out.println("2. BCrypt 암호화: " + passwordEncoding.encode(password));
		System.out.println("2. BCrypt 비교: " + passwordEncoding.matches(password, passwordEncoding.encode(password)));
	
	
	// ********************************************************************************** 
		//DB에 저장 된 값  1234 의 암호화
	
		//로기인 유저 암호화
	//DB에 저장된 first3 값과 로그할 유저가 넣는  1234 값 비교
		System.out.println(" 반환 값 :" + dbPassword("1234"));
		System.out.println("로그인 확인: " + passwordEncoding.matches("1234", dbPassword("1234")) );
	
	}
	
	
	
	//DB 에 변경해서 저장될 암호
	public String dbPassword(String loginPassword){
		
		SHAPasswordEncoder shaPasswordEncoder = new SHAPasswordEncoder(512);  
		shaPasswordEncoder.setEncodeHashAsBase64(true);
		PasswordEncoding passwordEncoding = new PasswordEncoding(shaPasswordEncoder);
		PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		passwordEncoding = new PasswordEncoding(passwordEncoder);

		//세번째 암호화
		String passwod =passwordEncoding.encode(loginPassword);
		return passwod;
	}
	
	
	
	
}

 

 

 

MYSQL 추가 DB에서 추가 암호 작업을 해보자

 

PASSWORD 함수도 있지만

 

mysql 에는 데이터를 암호화, 복호화하는 AES_ENCRYPT, AES_DECRYPT 함수가 있습니다. 이 암호화는 128비트 길이로 인코딩되어 저장됩니다. 그러나 소스를 수정해서 256비트까지 확장시킬수 있다고 합니다.

AES_ENCRYPT 는 문자열을 암호화하고, 바이너리 문자열을 반환하지만, AES_DECRYPT 는 암호화된 문자열을 복호화합니다. AES_DECRYPT 는 유효하지 않은 데이터는 padding을 감지하고, NULL을 반환합니다.
 

 # "암호화 키"는 임의의 값이 올 수 있으며, "문자열"은 암호화하고자 하는 값이 됩니다.

 # AES_ENCRYPT 암호화
  INSERT INTO 테이블명 VALUES (HEX(AES_ENCRYPT('문자열', '암호화 키')));
 
 # AES_DECRYPT 복호화
  SELECT AES_DECRYPT(UNHEX(필드명), '암호화 키') FROM 테이블명;


예제 (ex #1

 # AES_ENCRYPT 암호화
 INSERT INTO tbname VALUE (HEX(AES_ENCRYPT('123456','가나다라')));
 // 결과: 5A33E11DC0B638E4E5E74EBD52F55E3D

 # AES_DECRYPT 복호화
 SELECT AES_DECRYPT(UNHEX(필드명), '가나다라') FROM tbname;

 

이러한 방법으로 

다시 한번 2중으로 DB에서 암호를 해 봅시다.

컨트롤

 

비밀번호  1111 값으로  스프링으로 암호를 하였더니

값 이  : $2a$10$MZSbH9WT5QdBqP1BG5mp7ud0v8JWAYre/1OyvH5voB7RTcjbzH/.e   였다.

 

이것을 MYSQL 에서 다시   HEX(AES_ENCRYPT('$2a$10$MZSbH9WT5QdBqP1BG5mp7ud0v8JWAYre/1OyvH5voB7RTcjbzH/.e','java$$##1'))

으로 키값을 java$$##1 을 주고 암호를 해서 DB에 저장을 하였다.

 

INSERT INTO tbl_member (userid, userpw) 

    value ('admin' ,  HEX(AES_ENCRYPT('$2a$10$MZSbH9WT5QdBqP1BG5mp7ud0v8JWAYre/1OyvH5voB7RTcjbzH/.e','java$$##1')));

 

DB에 저장 된 값이 :

C7487C65CA7CC192AA636F828E78ADF36C95E96B0435401900AF5420F2AA4FEF0B971DC606FDC4E4491EE6EAE429CC3E27CF0B6CD4CB626A18C3EBAC8CF8CDEF

으로 나왔다.  1111 네자리 비밀번호가 130자리 수로 암호화 되어 저장 되었다.

 

	
@Inject
private PasswordEncoding passwordEncoding;
	


@RequestMapping(value="/login", method=RequestMethod.POST)
	public String login2(String userid, String userpw, HttpServletRequest request, RedirectAttributes rttr){
		
		
		
		try{	
			//DB에서 가져온 패스워드
			String dbPw=memberDAO.loginPasswd(userid);
			//내가 입력한 input 패스워드 와 매치 해서 비교
			//true 일치.
			logger.info("DB에서 가져온 dbpw 값: " +dbPw );
			if(passwordEncoding.matches(userpw, dbPw)){
				
				HttpSession session =request.getSession(false);
				MemberDTO dto =new MemberDTO();
				dto.setUserid(userid);
				dto.setUsername("홍길동");
				session.setAttribute("loginUser", dto);
				return "redirect:/";
			}else{
				rttr.addFlashAttribute("loginError", "아이디 또는 패스워드가 일치하지 않습니다.");	
				
				return "redirect:login";
			}
			
		}catch(Exception e){
			logger.info(e.getMessage());
			return "redirect:login";
		}
		
	}
	
	
	

 

	//DB에 있는 유저 아이디 와 DB에 저장 된 패스워드 가져오기
	@Override
	public String loginPasswd(String userid) {
		
	
		return sqlSession.selectOne(namespsce+".loginPasswd", userid);
	}

 

	
<!--	# AES_DECRYPT 복호화
?SELECT AES_DECRYPT(UNHEX(필드명), '가나다라') FROM tbname;  -->
	<select id="loginPasswd" resultType="string">
	   select AES_DECRYPT(UNHEX(userpw), 'java$$##1') from tbl_member where userid=#{userid} 
	</select>
	
	

 

 

 

about author

PHRASE

Level 60  머나먼나라

Ill got, ill spent. (부정하게 번 돈은 오래 가지 못한다.)

댓글 ( 8)

댓글 남기기

작성