springboot - blog project (51)

Yuri Lee·2020년 9월 1일
0

springboot - blog project

목록 보기
26/49

스프링부트 강좌 51강(블로그 프로젝트) - XSS 와 CSRF

XSS 이란? 자바스크립트로 공격하는 것이다.

게시판이 하나 있다. 글목록이 있는 게시판이다. 글쓰기 버튼이 밑에 하나 있는데 클릭하면 글쓰기 화면으로 갈 것이다. 여기서 글을 쓴다. 글쓰기 완료 버튼을 클릭한다. 글쓰기 완료버튼을 클릭하면 내가 적은 글이 하나 추가가 될 것이다.

글을 라고 적었다고 하자.

<script>
	for(var i =0; i<5000; i++){
    	alert("안녕")
   	}
</script>

해당 게시판에 딱 들어오면 alert 메시지가 5만번이 뜰 것이다. 그럼 사이트가 마비될 것이다. 이게 자바스크립트 공격이다. 이런 공격들을 막으려면 스크립트를 막거나 Lucy XSS Filter 를 사용하면 된다. 이와 같은 공격을 간단하게 막을 수 있다.

CSRF 공격은 무엇일까?

http://naver.com/admin/point?id=?&point=? 라는 주소가 있다고 가정하자.
만약 아이디가 ssar일 때 http://naver.com/admin/point?id=ssar&point=500000 라고 넣으면 네이버 포인트가 쌀 아이디에 500000포인트가 쌓인다고 한다. 그럼 당연히 필터를 하여 막아놓을 것이다.
시큐리티: /admin/**
-> 권한이 admin인 사람만 실행할 수 있도록 하는 것이다.
그럼 잘 막았다고 생각할 수 있는데..

게시판에 글을 쓴다고 가정해보자. 제목: 관리자님 급해요! 라는 제목..클릭하면 하이퍼링크라고 해서 어떤 이미지가 하나 있다. 내용에 그림 좀 클릭해서 확대해서 봐주세요!

관리자가 로그인을 하고 이 글을 본 것이다. 그리고 클릭해서 보고 그림을 클릭해서 봤는데..
주소가 하이퍼링크에

<a href="http://naver.com/admin/point?id=ssar&point=500000">
  <Img src="도라에몽.jpg"/>
</a>

관리자가 얘가 클릭했을 때 이 주소가 실행된다. 세션이 어드민이기 때문에 이 주소가 실행되고 공격을 당하는 것이다. 그래서 이것을 막기 위해 첫번째는 이런 요청을 get 방식이 아닌 post 방식으로 수행해야 한다. get 방식이 아닌 post 방식으로 실행할 경우 하이퍼링크로 공격하지 못하기 때문이다. 하이퍼링크는 무조건 get 방식이기 때문이다.

  • Referrer 검증 : 같은 도메인 상에서 요청이 들어오지 않는다면 차단하도록 한다.
  • CSRF Token 사용 :랜덤한 수를 사용자의 세션에 저장하여 사용자의 모든 요청에 대하여 서버단에서 검증하는 방법. 토큰을 사용하면 외부에서 들어오는 공격을 막을 수 있다.
package com.yuri.blog.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;


// 이 세개는 시큐리티의 세트이다... 이해가 안되면 그냥 하면 됨...^^
// 빈 등록: 스프링 컨테이너에서 객체를 관리할 수 있게 하는 것
@Configuration //빈등록(IoC관리)
@EnableWebSecurity // 시큐리티 필터가 등록이 된다. 
@EnableGlobalMethodSecurity(prePostEnabled = true) // 특정 주소로 접근을 하면 권한 및 인증을 미리 체크하겠다는 뜻.
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	 
	
	@Bean //IoC가 되요!!!
	// 이 함수가 리턴하는 new BCryptPasswordEncoder(); 이 값을 스프링이 관리한다. 필요할 때마다 가져다 사용하면 된다. 
	public BCryptPasswordEncoder encodePWD() {
		return new BCryptPasswordEncoder();
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.csrf().disable() // csrf 토큰 비활성화 (테스트 시 걸어두는 게 좋음)
			.authorizeRequests()
				.antMatchers("/","/auth/**","/js/**","/css/**","/image/**")
				.permitAll()
				.anyRequest() //이게 아닌 다른 모든 요청은 
				.authenticated()	//인증이 되어야 함
			.and()
				.formLogin()
				.loginPage("/auth/loginForm");
				
	}
}

저번 시간에 .csrf().disable() 를 사용했다. 우리가 요청하는 것은 form tag를 통해서 요청하는 게 아니라

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>

<%@ include file="../layout/header.jsp"%>

<div class="container">
	<form>
		<div class="form-group">
			<label for="username">Username:</label> 
			<input type="text" class="form-control" placeholder="Enter username" id="username">
		</div>
		
		<div class="form-group">
			<label for="pwd">Password:</label> 
			<input type="password" class="form-control" placeholder="Enter password" id="password">
		</div>
		
		<div class="form-group">
			<label for="email">Email address:</label> 
			<input type="email" class="form-control" placeholder="Enter email" id="email">
		</div>
		

	</form>
	<button id="btn-save" class="btn btn-primary">sign up</button>
</div>

<script src="/js/user.js"></script>
<%@ include file="../layout/footer.jsp"%>

위에 보이는 id="username", id="password", id="email" 의 id 값으로 적혀있는 값들을 들고온다. 들고와서 ajax를 통해 요청한다.

let index = {
    init: function(){
        $("#btn-save").on("click", ()=>{ // function(){} , ()=>{} this를 바인딩하기 위해서!! 
            this.save();
        });
    },

    save: function(){
        //alert('user의 save함수 호출됨');
        let data = {
                username: $("#username").val(),
                password: $("#password").val(),
                email: $("#email").val()
        };
        
        //console.log(data);
        
        // ajax호출시 default가 비동기 호출
        // ajax 통신을 이용해서 3개의 데이터를 json으로 변경하여 insert 요청!!
        // ajax가 통신을 성공하고 서버가 json을 리턴해주면 자동으로 자바 오브젝트로 변환해주네요.
        $.ajax({ 
            type: "POST",
            url: "/auth/joinProc",
            data: JSON.stringify(data), // http body데이터
            contentType: "application/json; charset=utf-8",// body데이터가 어떤 타입인지(MIME)
            dataType: "json" // 요청을 서버로해서 응답이 왔을 때 기본적으로 모든 것이 문자열 (생긴게 json이라면) => javascript오브젝트로 변경
        }).done(function(resp){
            alert("회원가입이 완료되었습니다.");
            //console.log(resp);
            location.href = "/";
        }).fail(function(error){
            alert(JSON.stringify(error));
        }); 
        
    }
}
index.init();

이런 자바스크립트 요청이 들어올때 CSRF Token이 없기 때문에 스프링 시큐리티가 기본적으로 접근을 막아버린다. 요청시에 토큰 없이 JSON.stringify(data) json 데이터만 날려서 요청을 했다. 그러면 막히기 때문에 테스트 시에는 .csrf().disable() 을 걸어줘야 한다.

-이 글은 유투버 겟인데어의 스프링 부트 강좌를 바탕으로 정리한 내용입니다.-

profile
Step by step goes a long way ✨

0개의 댓글