#클라이언트 인증 (http 기본 인증)

http는 기본적으로 stateless (무상태)이다. stateless라서 세션을 유지하기 위해서 쿠기 메커니즘을 사용한다.

하지만 안드로이드나 IOS기기 또는 CURL 등 다양한 클라이언트들이 쿠키 메커니즘이 동작한다고 보장 할 수 없다.

세션을 유지하지 않고, 요청할 떄마다 인증 정보를 제시하고 사용자를 식별하면 된다.

서버에 요청할 때마다 Authorization 요청 헤더에 인증 정보를 담아서 보낸다. 

1. http 기본 인증 

Header : POST /v1/articles HTTP/1.1
HOST : localhost
Authiruzation : Basic 12389sfdjiookasdy9849sdui== -- base61_encode
Accept : application/json
Content-Type : application/json 

{ "title":"글",
  "content":"몰라요"
}


- 기본 인증의 한계 (여러 가지 보안 취약점을 가지고 있다.)

1. 아이디와 비밀번호를 클라이언트 애플리케이션에 저장해야 한다. 
   개인 컴퓨터면 문제가 되지 않지만 공용 기기라면 완전히 다른 얘기가 된다. 

2. 평문으로 되어 있다.
   네트워크단에서 탈취 할 수도 있다. 다른 네트워크 도구 뿐 아니라, 브라우저의 개발자 도구로도 헤더를 볼수 있다. 

* 암호화가 가능 ,https 프로토콜을 이용하여 해결 가능 , 인트라넷처럼 제한된 환경에서 http 기본 인증 가능



#JWT
클라이언트 서버
1.CreateToken{ID:xx PW:xx} ----------------------------------------> 2. Token 생성 및 Store (저장)
        4. Tocken 저장      <----------------------------------------- 3.  tocken 
5.  Authorization 요청 헤더에 토큰을 달아서 보낸다(API호출 등) ----> 6. 유효성 확인 후 결과 전송 ( API 응답 , 로그인 등) 
7.  result                      <----------------------------------------  result

* 60 ~ 120분 적당(?)

#cors 동일 출처 보안 정책 (브라우저에서 이를 막음)
SPA ex) react 3000 port --> node 5000 port 

기본적으로 프로토콜,호스트명,포트 아 같은 Same-Origin에서의 접근이 가능하지만 다른 도메인
Adomain.page1.html -> Adomain.page2.html   Same-Origin

Adomain.page.html  -> Bdomain.page.html     Cross-Origin

서버에서 허용하여 주는 것으로 해결



# 보안 정책
1.사용량 제한

    특정 클라이언트가 API를 과도하게 사용하면 다른 클라이언트가 피해를 본다. 그뿐만 아니라 사용량 제한은 디도스 공격, 사전 공격 등으로부터 서비스를 보호하기도 한다.
    그래서 지정한 시간 동안 요청할 수 있는 횟수를 제한하는 방법 

2.리소스 아이디 난독화

    auto_increment를 기본키로 사용할 경우, 서비스가 커지면 자동 증가 아이디도 공격의 대상이 될 수 있다. 

-API로 응답받은 리소스의 아이디로 다른 리소스를 탐색 할 수 있다, 하지만 인증이나 인가 기능이 막아준다.
-아이디 번호를 하나씩 올려가며 리소스 전체를 긁어 갈 수 있다.
-사용자 아이디를 하나씩 올려 가며 서비스의 전체 사용자 수를 예측할 수 있다.

UUID를 사용하거나, 난수를 사용한다 


#CSRF(사이트간 요청 위조)
악성코드 서버에서 발생

공격과정 
...

http://auction.com/changeUserAcoount?id=admin&password=admin" width="0" height="0">
...
위 옥션 사건을 예로 들어보자.

옥션 관리자 중 한명이 관리 권한을 가지고 회사내에서 작업을 하던 중 메일을 조회한다. (로그인이 이미 되어있다고 가정하면 관리자로서의 유효한 쿠키를 갖고있음)
해커는 위와 같이 태그가 들어간 코드가 담긴 이메일을 보낸다. 관리자는 이미지 크기가 0이므로 전혀 알지 못한다.
피해자가 이메일을 열어볼 때, 이미지 파일을 받아오기 위해 URL이 열린다.
해커가 원하는 대로 관리자의 계정이 id와 pw 모두 admin인 계정으로 변경된다.

위 공격과정 출처 : https://sj602.github.io/2018/07/14/what-is-CSRF/

해결방법 
1. referrer 검증 - 같은 도메인 상에서 요청이 들어오지 않으면 차단
2.csrf 토큰 - 랜덤한 수를 사용자의 세션에 저장하여 사용자의 모든 요청에 대하여 서버단에서 검증하는 방법
3. captcha 이용하여 cahtcha 이미지상의 숫자/문자가 아니면 해당 요청을 거부

#XSS 
악성코드 클라이언트에서 발생
사용자를 대상으로 한 공격이다.

ex) input에  를 넣어 보냄 
해결방법 
입력 값 제한
입력 값 치환
필터 사용 등

 


# 파일 첨부 기능 (파일 업로드)

* form http 폼 전송의 인코딩 타입을 멀티파트/폼 데이터(multipart/form-data)로 바꾸어야 한다. 이 속성을 추가하지 않으면 파일은 전송 되지않고, 파일 이름만 전송된다.

첨부파일 저장 파일 만들 경우, 권한 잘 적용하여야 하고 git에 올라가는걸 방지 하자.

사용자 업로드 후 form 전송 -> 유효성 체크(원하는 형식인지 (MIMES:jpg,zip....) -> 같은 이름의 파일을 여러번 올릴 수 있기 때문에 구분값 (스트링랜덤값?..)등 필요 
   


# 쿼리 캐싱

사용자가 어떤기능을 사용할떄 가장 느린 부분은 데이터베이스를 사용하는 부분이다. 이처럼 비용이 높은 곳을 더싼 저장소로 대체하는 행위를 캐싱이라고 한다.
캐시 저장소는 보통 키-값으로 구성된다. 파일일 수도 있고, 메모리일 수도있다. 데이터베이스 접근을 요하는 컨트롤러 메서드에 사용자 요청이 도달하면, 컨트롤러는 요청 정보를 
이용해서 캐시 키를 만든다. 캐시 키로 저장소를 조회해서 찾으면 그 값을 사용한다. 이것을 캐시 힛이라고한다.
캐시 키를 찾지 못하면, 그 결과를 데이터베이스에 저장한다. 이 작업을 캐시 미스, 캐시 필 이라고 한다. 

하지만 메모리 캐시를 저장소를 사용하면 파일 시스템에 접근하는 오버헤드까지도 줄일 수 있다 이를 위한 데이터베이스는 멤캐시,레디스 등이 있다.




   

# CRUD

게시글과 사용자 일대다 관계 
게시글과 첨부파일 일대다 관계
게시글과 태그 다대다관계 

댓글 사용자 일대다 관계
댓글 대댓글 일대다 관계 (댓글 하나당 여러 대댓글 가능)
좋아요 싫어요 하나의 댓글에 같은 사용자가 여러번 투표하는 것을 막히 위해서 사용자를 식별 해야 한다.

댓글에 대댓글이 있을 경우 댓글이 삭제 되면 자식은 고아가된다 그래서 데이터에베이스의 논리적 삭제를 사용한다. (삭제 플래그를 남김)
그래서 댓글은 삭제 하고, 삭제되었다는 글을 출력하여 준다.

(more - 3가지 경우 1. 삭제된 댓글이면서 대댓글도 없다. 이때는 아무것도 출력할 필요가 없다.
 2. 삭제된 댓글이지만 대댓글이 있따. 삭제되었다는 글을 표시하고 대댓글은 계속 출력.
 3. 살아 있는 댓글 이다, 자신도 출력하고, 자식 댓글도 계속 출력한다.)

MORE

# 인증과 인가

제가 아는 내용 :  

          인가란, 인증된 사용자가 권한(접근권한 등)이 있는지 확인 하는 것  
          인증이란, 사용자 본인이 맞는지 확인 하는것

 

절차 : 인증 후 -> 인가


- 실생활에서 예를 들면, 어느 연구소에 처음 출근하는 사용자가 출입을 희망 한다고 가정하자, 사용자는 연구소에 처음 왔기 때문에 출입권한이 없다. 이 과정에서 연구소의 직원으로 등록하여 
 
권한을 주는 것이 바로 인가이고, 직원으로 등록 되었기 때문에 출입이 가능하여 이 것을 인증 되었다고 한다.

- 실제 Web 서비스에서 예를 들면,  인증된 사용자가 아니면, 즉 로그인 하지 않은 사용자는 글을 작성하고 수정하고 삭제 할수 없다 또, 인가된 사용자가 아니면(권한이 부여된) 로그인한 사용자라도 글 작성, 수정, 삭제를 할 수있지만 

자신이 작성하지 않은 글도 수정 이나 삭제 할 수있으면 안된다.   

라라벨에 auth middleware, 스프링에 security 내장된 기능을 사용 할 수 있다.

회원가입

가입 확인 절차

- 사용자 등록 폼을 처리할 때, 사용자가 등록한 이메일 주소로 활성화 코드를 포함한 가입 확인 메일을 보낸다.
- 메일에는 가입 확인을 위햇 우리 서비스로 다시 들어오는 URL을 포함하는데, URL에 포함된 활성화 코드로 사용자를 찾아서 사용자 정보를 업데이트한다.
  (URL ex auth/confirm/{code}  , 60바이트 랜덤문자 )

사용자 테이블에 confirm_code와 , 가입 확인 여부(activated) 

즉, 사용자 form 전송 -> (정상적인 값인지 체크 후)  -> 사용자 테이블에 활성화 코드를 기록(60바이트 랜덤 문자) -> 가입 확인 메일 전송 -> confirmcode로 확인 
-> confirm code = null, activated =1   

고려사항 : 이미 로그인한 사용자가 회원가입 주소를 직접 입력 하는 것을 막아야함
             ex) 기본사용자는 'guest' redirect 

 

 


소셜 로그인 작동원리


웹 브라우저  웹 서버  소셜
1  ------------------------------------------------------->
2  <-------------------------------------------------------

3 ------------------------------------------------------------------------------------------------------------------------->
4 <-------------------------------------------------------------------------------------------------------------------------

5 -------------------------------------------------------------------------------------------------------------------------->
6 <--------------------------------------------------------------------------------------------------------------------------

7------------------------------------------------------------>
8<-----------------------------------------------------------

ex) 구글로 로그인

1. 사용자가 구글로 로그인 버튼을 클릭한다.
2. 웹 서버가 구글로 로그인 페이지를 띄운다.

3. 사용자가 구글 아이디와 비밀번호를 입력하여 구글에 로그인을 요청한다.
4. 구글이 사용자에게 이용하는 사이트에 제공 할 정보, application에 승인 할 것을 물어보는 페이지를 띄운다.

5. 사용자가 제공 정보 및 구글로 로그인 허락한다 
6. 구글에서 쿼리스트링으로 코드(토큰?)이 redirect로 반환된다.

7. 최초 구글에서 제공된 정보와 일치하는 사용자가 있으면 로그인 하고, 아니면 회원가입을 한다.
8. 해당 사용자로 로그인 처리를 하고, 자사 서비스 홈페이지로 redirect 한다.

   

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));



int num = Integer.parseInt(br.readLine());
int[] p = new int[num+1];
int[] dp = new int[num+1];


for(int i =0;i<num;i++) {

p[i]=Integer.parseInt(br.readLine());

}



dp[0]=0;
dp[1]=p[1];
if(num>1)
dp[2]=p[1]+p[2];

for(int i=3;i<=num;i++) {

dp[i]=Math.max(dp[i-1],Math.max(dp[i-2]+p[i],dp[i-3]+p[i-1]+p[i]));

}


bw.write(dp[num]+"\n");



bw.flush();
br.close();
bw.close();
}

 

 

참고한 블로그

https://debuglog.tistory.com/80

'알고리즘' 카테고리의 다른 글

백준 10818번 자바(JAVA)  (0) 2019.10.15
백준 11721 자바(JAVA)  (0) 2019.10.14
백준 11719 자바(JAVA)  (0) 2019.10.14
백준 11718 자바(JAVA)  (0) 2019.10.14
백준 10818번 자바(JAVA)  (0) 2019.10.14

public static void main(String[] args) throws Exception {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));


int input = Integer.parseInt(br.readLine());


String value =br.readLine();
int min=Integer.parseInt(value.split(" ")[0]);
int max=min;

for(int i=1;i<input;i++) {

int val=Integer.parseInt(value.split(" ")[i]);

if(min>val)
min =val;
if(max<val)
max=val;

}

bw.write(Integer.toString(min)+" "+Integer.toString(max));


bw.flush();
br.close();
bw.close();
}

 

// 1번 시간초과 코드

 

여기서는 MATH의 MAX와 MIN 함수를 사용하라는 것 같다.

 

 



public static void main(String[] args) throws Exception {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));


int input = Integer.parseInt(br.readLine());

StringTokenizer str = new StringTokenizer(br.readLine(), " ");

int max=Integer.MIN_VALUE;
int min=Integer.MAX_VALUE;



while(str.hasMoreTokens()) {

int num = Integer.parseInt(str.nextToken());

min=Math.min(min, num);
max=Math.max(max, num);

}


bw.write(String.valueOf(min)+" "+String.valueOf(max));

bw.flush();
br.close();
bw.close();
}

//성공코드

 

'알고리즘' 카테고리의 다른 글

백준 2156번 자바(JAVA)  (0) 2019.10.22
백준 11721 자바(JAVA)  (0) 2019.10.14
백준 11719 자바(JAVA)  (0) 2019.10.14
백준 11718 자바(JAVA)  (0) 2019.10.14
백준 10818번 자바(JAVA)  (0) 2019.10.14

public static void main(String[] args) throws Exception {


BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

String input = br.readLine();



if(input.length()<10)
bw.write(input.substring(0,input.length()));
else if(input.length()>= 10) {

if(input.length()%10 == 0) {
int k=0;
for(int i=1;i<=input.length()/10;i++) {

bw.write(input.substring(k,i*10));
bw.write("\n");
k=i*10;
}
}

else {
int i;
int k=0;


for(i=1;i<=input.length()/10;i++) {

bw.write(input.substring(k,i*10));
bw.write("\n");
k = i*10;
}


bw.write(input.substring((i-1)*10,(i-1)*10+input.length()%10));

}

}

bw.flush();
bw.close();
br.close();

}

'알고리즘' 카테고리의 다른 글

백준 2156번 자바(JAVA)  (0) 2019.10.22
백준 10818번 자바(JAVA)  (0) 2019.10.15
백준 11719 자바(JAVA)  (0) 2019.10.14
백준 11718 자바(JAVA)  (0) 2019.10.14
백준 10818번 자바(JAVA)  (0) 2019.10.14

public static void main(String[] args) throws Exception {


BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

int num = Integer.parseInt(br.readLine());
String str = new String(br.readLine());

int sum =0;
for(int i=0;i<num;i++) {


if(i==num) {

sum += Integer.parseInt(str.substring(i, i));
break;
}

else {
sum += Integer.parseInt(str.substring(i, i+1));
}




}


bw.write(sum+"\n");


bw.flush();
bw.close();
br.close();

}

'알고리즘' 카테고리의 다른 글

백준 10818번 자바(JAVA)  (0) 2019.10.15
백준 11721 자바(JAVA)  (0) 2019.10.14
백준 11718 자바(JAVA)  (0) 2019.10.14
백준 10818번 자바(JAVA)  (0) 2019.10.14
프로그래머스/LEV2 타겟 넘버 자바  (0) 2019.10.10

public static void main(String[] args) throws Exception {


BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));


while(true) {

String str = br.readLine();

if(str ==null) {

break;
}

bw.write(str);
bw.write("\n");
bw.flush();

}



bw.close();
br.close();

}

'알고리즘' 카테고리의 다른 글

백준 11721 자바(JAVA)  (0) 2019.10.14
백준 11719 자바(JAVA)  (0) 2019.10.14
백준 10818번 자바(JAVA)  (0) 2019.10.14
프로그래머스/LEV2 타겟 넘버 자바  (0) 2019.10.10
백준 1110번 자바 성공코드  (0) 2019.06.20
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
public class Main {
 
    
 
    public static void main(String[] args) throws Exception {
 
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        
        
        
        while(true) {
            StringTokenizer str = new StringTokenizer(br.readLine());
            
            
            
            int input1 = Integer.parseInt(str.nextToken());
            int input2 = Integer.parseInt(str.nextToken());
            
            if(input1 ==0 &&  input2==0)
                break;
            
            
            bw.write(input1+input2+"\n");
            
            
            bw.flush();
        }    
            
        
        
        
        
            
        
        
    }
    
    
 
}
 
 
 

'알고리즘' 카테고리의 다른 글

백준 11719 자바(JAVA)  (0) 2019.10.14
백준 11718 자바(JAVA)  (0) 2019.10.14
프로그래머스/LEV2 타겟 넘버 자바  (0) 2019.10.10
백준 1110번 자바 성공코드  (0) 2019.06.20
백준 4344 자바 성공코드  (0) 2019.06.20

+ Recent posts