• CORS(Cross Origin Resource Sharing)는 주로 다른 원본의 컨텐츠에 대한 액세스 권한을 유효성 검증하기 위해 브라우저에서 사용하는 메커니즘

CORS의 개념

  • 브라우저가 웹 페이지를 로드할 때 CORS(동일 출처 정책)을 적용 → 웹 페이지와 동일한 원본에서만 컨텐츠를 패치하도록 허용
  • 경우에 따라서는 웹 페이지에서 해당 웹 사이트를 신뢰하는 여러 원본의 자산에 대한 액세스가 필요 → CORS를 사용
  • Chrome, Firefox 및 Safari 등의 거의 모든 현대 브라우저는 CORS 구현 → CORS와 관련한 원본이 CDN 원본과 동일할 필요 X
  • CORS의 원본은 URI 스킴, 도메인 및 가능한 임의의 포트 번호에 의해 정의
  • CDN은 브라우저 관점에서 CORS 원본으로 간주될 수 있음


CDN에 대한 CORS 설정

  • CDN은 원본의 CORS 설정에 대해 투명함으로 특정 CDN 구성이 필요 X
  • CDN edge 서버가 일부 컨텐츠의 첫 번째 요청에 대해 캐시된 응답을 찾지 못하는 경우 해당 요청을 원본 호스트에 전달 → 원본 서버가 CORS 요청을 처리하도록 설정
  • 요청에 Origin 헤더가 있는 경우 Access-Control-Allow-Origin의 CORS 헤더 및 연관된 값을 사용하여 에지에 다시 응답
  • 해당 헤더 및 값을 포함하는 전체 응답이 CDN에서 캐시
  • 동일한 URI 경로에 있는 오브젝트에 대한 후속 요청이 캐시에서 수행 → 원래 원본에서 수신된 Access-Control-Allow-Origin 헤더 값이 포함

다중 CORS 원본 지원

  • 경우에 따라 특정 원본(전부는 아님)목록이 CDN 컨텐츠에 액세스하도록 허용 → CDN에서 다른 원본의 다른 Access-Control-Allow-Origin 응답 헤더를 제공 필요
  • 원본의 와일드카드 * 아님
  • CDN은 컨텐츠와 함께 헤더를 캐시하므로 일치하지 않을 수 있는 요청에 캐시된 Access-Control-Allow-Origin 헤더를 제공
  • 캐시 키 조회 최적화를 활용하여 다른 원본의 URL에서 다른 매개변수를 추가 가능 → 컨텐츠 및 헤더가 다르게 캐시
  • CDN은 백엔드 서버에서 제공하는 다른 Access-Control-Allow-Origin 헤더를 리턴
  • abc.com 원본의 요청은 access-control-allow-origin: https://abc.com을 리턴
    $ curl -H "Origin: https://abc.com" -H "Referer: https://abc.com/" -i https://cdn.example.com/test.json?domain=abc.com
    HTTP/2 200
    access-control-allow-origin: https://abc.com
    access-control-allow-methods: GET
    access-control-allow-credentials: true
    ### 생략 ###
  • 123.com 원본의 요청은 access-control-allow-origin: https://123.com을 리턴
    $ curl -H "Origin: https://123.com" -H "Referer: https://123.com/" -i https://cdn.example.com/test.json?domain=123.com
    HTTP/2 200
    access-control-allow-origin: https://123.com
    access-control-allow-methods: GET
    access-control-allow-credentials: true
    ### 생략 ###


Origin(Request) 헤더에 따른 CORS 설정

  • Client에서 Request 헤더에 Origin 헤더를 요청 하는데, 해당 헤더에 맞추어 CORS 헤더를 응답받기를 원함
    ## Origin 헤더가  ' *.hippo.com' 인 경우
    ## aaa.hippo.com이면 CORS 헤더를 aaa.hippo.com 으로 응답
    ## bbb.hippo.com이면 CORS 헤더를 bbb.hippo.com 으로 응답
  • Nginx 설정
    ###Location Block
          if ($http_origin ~ hippo.com) {
          more_set_headers "Access-Control-Allow-Origin  $http_origin";
    }
  • 응답 헤더 확인
    $ curl -D- -o/dev/null -H'host:hippo.cdn.co.kr' 127.0.0.1/sample.txt -H 'Origin:https://aaa.hippo.com'
    Server: nginx
    Date: Tue, 25 Feb 2020 04:53:45 GMT
    Content-Type: text/plain; charset=utf-8
    Content-Length: 1641
    Connection: keep-alive
    Last-Modified: Thu, 06 Feb 2020 03:24:17 GMT
    ETag: "1"
    Access-Control-Allow-Origin: https://aaa.hippo.com


CORS 등장 배경

  • 과거 웹사이트를 만들 때, 대부분 하나의 서버에서 브라우저의 모든 요청을 처리
  • 점점 웹사이트가 발전하여서 웹사이트에서 할수있는 일이 많아졌음(ex 날씨 api 를 이용하여 기능을 넣을 필요가 있는 경우)
  • 웹브라우저와 날씨 api 도메인이 서로 달라서 요청을 주고받을 수 없음 → 서로 도메인이 달라 과거에는 해당 문제를 해결하기 위한 JSONP 방식 사용
  • JSONP 방식은 <script> 요소를 사용하여 외부 출처로부터 조회된 내용을 실행하는 것이 허용 → 조회된 내용을 서버에 데이터로 반환하는 용도로 사용
  • JSONP 방식 예제 → CORS가 나오기 전까지 사용 되던 방식으로 보안상 이슈로 사용 X

    # 함수이름을 넣어 요청
    const script = document.createElement("script")
    script.src = "ingg.com/test.json?callback=parseResponse"
    
    # 서버에서는 함수이름을 넣고 매개변수로 데이터를 넣어서 반환
    parseResponse({
    "id" : "123",
    "name" : "ingg",
    })
    
    function parseResponse(data){
      // ...
    }

CORS란

  • CORS는 다른 출처의 리소스가 필요한 경우, SOP를 우회하기 위한 여러가지 방법 중 가장 권장되는 방법
  • 교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. - MDN


SOP 정책

SOP 정책이란

  • Same Origin(동일 출처 정책)은 scheme, host, port가 모두 같을 때를 의미
  • SOP(Same-Origin Policy)란 같은 Origin에서만 리소스를 공유할 수 있다는 규칙
  • Same Origin Policy(동일 출처 정책)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식
  • Same Origin(동일 출처 정책)은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여줌
  • 브라우저에서 다른 서버에 요청할 경우 SOP 정책 영향을 받음
  • 브라우저를 거치지 않고 서버 간 통신을 할 때는 SOP 정책이 적용 X

SOP 정책이 존재이유

  • 다른 출처의 어플리케이션이 서로 통신하는 것에 대해 제약
  • 악의를 가진 사용자가 소스 코드를 보고 CSRF(Cross-Site Request Forgery) 나 XSS(Cross-Site Scripting)와 같은 방법을 사용하여 정보를 탈취를 하는 것을 막음


CORS 동작 방식

  • CORS 접근 제어 시나리오 (교차 출처 리소스 공유가 동작하는 방식)에는 크게 세가지
    1. 프리플라이트 요청 (Preflight Request)
    2. 단순 요청(Simple Request)
    3. 인증정보 포함 요청(Credentialed Request)

1. 프리플라이트 요청 (Preflight Request)

  • Preflight Request는 요청을 예비 요청과 본 요청으로 나눔
  • OPTIONS 메서드를 통해 다른 도메인의 리소스에 요청이 가능한지 (실제 요청이 전송하기에 안전한지) 확인 작업을 하고, 요청이 가능하다면 실제 요청을 보냄
  • Cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 Preflight 요청
  • Preflight Request
    • OPTIONS 요청과 함께 두 개의 다른 요청 헤더가 전송
    • Preflight Request가 완료되면 실제 요청을 전송
    • 첫 번째 행은 실제 요청을 전송할 때 POST 메서드로 전송된다는 것을 서버에 알려줌
    • 두 번째 행은 실제 요청을 전송 할 때 X-PINGOTHER 와 Content-Type 사용자 정의 헤더와 함께 전송된다는 것을 서버에 알려줌
      Access-Control-Request-Method: POST                                     # 실제요청의 메서드
      Access-Control-Request-Headers: X-PINGOTHER, Content-Type  # 실제요청의 추가헤더
  • Preflight Response
    • 서버가 메서드와 헤더를 받을 수 있음을 알려줌
    • 첫 번째 행은 응답할 때 서버측 허가되는 서버 도메인(http://foo.example)를 클라이언트에게 알려줌
    • 두 번째 행은 응답할 때 서버측 허가되는 POST, GET, OPTIONS 메서드를 클라이언트에게 알려줌
    • 세 번째 행은 응답할 때 서버측 허가되는 X-PINGOTHER 와 Content-Type 사용자 정의 헤더를 클라이언트에게 알려줌
    • 마지막 행 은 preflight request에 대한 응답을 캐시할 수 있는 시간(초)를 클라이언트에게 알려줌 → 86400초 (=24시간)
    • Preflight를 보내면 사전, 실제 요청 두번이 매번 왔다갔다 하므로 브라우저가 캐싱을 해두고 똑같은 요청을 보낼 때에는, 사전 요청을 보내지 않고 바로 본 요청을 보냄
      Access-Control-Allow-Origin: http://foo.example                    # 서버측 허가출처
      Access-Control-Allow-Methods: POST, GET, OPTIONS              # 허가 메서드
      Access-Control-Allow-Headers: X-PINGOTHER, Content-Type   # 서버측 허가헤더
      Access-Control-Max-Age: 86400                                           # Prefilght 응답 캐시기간

2. 단순 요청(Simple Request)

  • Simple Request는 Preflight Request와 다르게 요청을 보내면서 즉시 cross origin인지 확인
  • Simple Request는 아래 조건을 모두 충족해야함
    1. 메서드는 GET POST HEAD 중 하나
    2. 헤더는 Accept, Accept-Language, Content-Language, Content-Type만 허용
    3. Content-Type 헤더는 다음의 값들만 허용
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain


3. 인증정보 포함 요청(Credentialed Request)

  • 인증 관련 헤더를 포함할 때 사용하는 요청
  • 브라우저가 제공하는 비동기 리소스 요청 API인 XMLHttpRequest 객체나 fetch API는 별도의 옵션 없이 브라우저의 쿠키 정보나 인증과 관련된 헤더를 기본적으로 요청에 담지 않으므로, credentials 옵션을 변경하지 않고서는 cookie를 주고 받을 수 없음
  • 인증정보 포함 요청의 세가지 옵션
    1. omit → 절대로 cookie들을 전송하거나 받지 않음
    2. same-origin → 동일 출처(same origin)이라면, user credentials (cookies, basic http auth 등..)을 전송 (default 값)
    3. include → cross-origin 호출이라 할지라도 언제나 user credentials (cookies, basic http auth 등..)을 전송
  • credentials 설정을 include/true로 설정하면 CORS정책에 의해 Access-Control-Allow-Origin을 모든 출처를 허용하는 * 로 지정할 수 없다는 에러가 발생
  • CORS 설정에서 *을 입력하여 모든 출처를 허용한 경우에는 특정 출처를 정확히 명시
  • 인증 정보 포함하여 요청하는 예시
    fetch('주소', {
    credentials: 'include', // 모든 요청에 인증 정보 포함
    });
  • axios 로 통신할 시, withCredentials 설정을 true 로 넣어주면 됨

    axios.post(주소, 데이터, { withCredentials: true });
    
    // 또는 공통으로 추가
    axios.defaults.withCredentials = true;



CORS 해결 방법

  • CORS 정책 위반으로 에러가 발생했을때 해결하는 방법

1. Access-Control-Allow-Origin 응답 헤더 세팅

  • 서버측 응답에서 접근 권한을 주는 헤더를 추가하여 해결
    app.use((req, res, next) => {
    res.header("Access-Control-Allow-Origin", "*");                               // 모든 도메인
    res.header("Access-Control-Allow-Origin", "https://example.com");  // 특정 도메인
    });

2. CORS 모듈 사용

  • 아무 옵션없이 설정하면 모든 cross-origin 요청에 대해 응답 → 특정 도메인이나 특정 요청에만 응답하게 옵션을 설정하는 것이 좋음

    const cors = require("cors");
    const app = express();
    
    app.use(cors());
  • 특정 도메인 접근 혀용

    const options = {
      origin: "http://example.com",        // 접근 권한을 부여하는 도메인
      credentials: true,                          // 응답 헤더에 Access-Control-Allow-Credentials 추가
      optionsSuccessStatus: 200,           // 응답 상태 200으로 설정
    };
    
    app.use(cors(options));
  • 특정 요청 접근 허용
    app.get("/example/:id", cors(), function (req, res, next) {
      res.json({ msg: "example" });
    });

3. webpack-dev-server proxy 기능

  • 리액트 개발환경에서, 서버쪽 코드를 수정하지 않고 해결 가능

  • 아래와 같이 프록시 속성을 설정하면, 서버에서 해당 요청을 받아줌

  • 중간의 프록시 서버 덕분에, domain.com 서버에서는 같은 도메인(domain.com)에서 온 요청으로 인식하여 CORS 에러가 발생 X

    // 프록시 쓰지 않았을때
    // localhost:8080(클라이언트 측) --X (CORS)--> domain.com (서버 측)
    
    // 프록시를 설정 후
    // localhost:8080(클라이언트 측) --O 프록시가 설정된 Webpack Dev Server--> domain.com (서버 측)
    
    module.exports = {
      devServer: {
        proxy: {
          "/api": {
            target: "domain.com",
            changeOrigin: true,
          },
        },
      },
    };

4. package.json에 proxy 값을 설정

  • create-react-app으로 생성한 프로젝트에서는, package.json에 proxy 값을 설정하여 proxy 기능을 활성화하는 방법
    {
      //...
      "proxy": "http://localhost:4000"
    }

  • crontab 명령어는 사용자가 주기적인 작업을 등록하기 위해 사용
  • crontab 명령어 형식
    $ crontab [option] 파일명

1. crontab의 옵션


2. crontab 기본 (crontab basic)

  • 기본이 되는 크론탭 사용법
  • 편집할 수 있는 곳이 로딩 → 크론탭을 설정할 수 있는 장소에 접근

2.1. crontab -e 명령어를 통해 crontab 파일 수정

  • 각종 크론탭 명령어를 입력후 콜론(:) 입력 후에 wq 를 입력해 크론탭을 갱신

    1. wq로 저장하면 "crontab: installing new crontab"이 출력

    2. q로 저장하면 "crontab: no changes made to crontab" 출력

      $ crontab -e
      
      # crontab을 통해 편집할 수 있는 곳에 접근
      */3 * * * * /opt/fujitsu/ServerViewSuite/RAIDManager/svrack/svrack.sh -c
      
      # srvmagtCron: restarts daemons that died
      0,15,30,45 * * * * /bin/sh -c "[ -x /etc/srvmagt/srvmagtCron ] && /etc/srvmagt/srvmagtCron"
  • crontab -e 입력 후 다음과 같은 내용을 입력 → crontab 갱싱

    1. 별이 다섯개 뒤에 명령어 입력 → "매분마다 실행" 별이 지칭하는 것"

    2. 쉘스크립트 뿐만 아니라 리눅스 커맨드도 사용 가능

      $ crontab -e
      
      # crontab 파일 내용
      * * * * * ls -al
      
      # crontab 파일 내용을 수정한 후 wq!로 저장하면 아래의 내용 출력
      no crontab for root - using an empty one
      crontab: installing new crontab
      
      # * * * * * 를 적용해서 매분마다 ls -al 실행

2.2 crontab -l 명령어를 통해 crontab 파일 읽기

  • 현재 crontab에 어떤 내용이 들어있는지 확인

  • cat 명령어로 파일을 읽어들인 것처럼 표준 출력으로 크론탭 내용을 출력

    $ crontab -l
    */3 * * * * /opt/fujitsu/ServerViewSuite/RAIDManager/svrack/svrack.sh -c
    
    # srvmagtCron: restarts daemons that died
    0,15,30,45 * * * * /bin/sh -c "[ -x /etc/srvmagt/srvmagtCron ] && /etc/srvmagt/srvmagtCron"

2.3 crontab -r 명령어를 통해 crontab 파일 삭제

  • crontab -r 명령어를 통해 crontab 파일의 모든 내용 삭제

    # crontab 삭제
    $ crontab -r
    
    # 삭제되었는지 crontab 확인
    $ crontab -l
    no crontab for root



3. 주기 결정

  • 각 별 위치에 따라 주기를 다르게 설정 가능

  • 순서대로 분-시간-일-월-요일 순서

  • 괄호 안의 숫자 범위 내로 별 대신 입력 가능 → 숫자로 기간 결정

  • 요일은 0부터 7까지 숫자로 표기

    1. 0과 7이 일요일

    2. 1은 월요일

    3. 2는 화요일

    4. 3은 수요일

    5. 4는 목요일

    6. 5는 금요일

    7. 6은 토요일

      # Example of job definition:
      # .---------------- minute (0 - 59)
      # |  .------------- hour (0 - 23)
      # |  |  .---------- day of month (1 - 31)
      # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
      # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
      # |  |  |  |  |
      # *  *  *  *  * user-name command to be executed
      
      *      *      *      *      *
      분(0-59)  시간(0-23)  일(1-31)  월(1-12)   요일(0-7)



4. 주기별 예제

  • 주기 입력 방법엔 * , - , / 을 이용
  • 각각의 특수기호가 하는 기능이 다름
    1. * : 모든
    2. - : 3-5로 하면 3에서 5까지 기간을 지정
    3. / : 분에 */10을 하면 10분마다 반복할 수 있게 지정
  • 조합을 어떻게 하느냐에 따라 입맛대로 주기를 설정 가능

4.1. 매분 실행

# 매분 test.sh 실행
* * * * * /home/script/test.sh

4.2. 특정 시간 실행

# 매주 금요일 오전 5시 45분에 test.sh 를 실행
45 5 * * 5 /home/script/test.sh

4.3. 반복 실행

# 매일 매시간 0분, 20분, 40분에 test.sh 를 실행
0,20,40 * * * * /home/script/test.sh

4.4. 범위 실행

# 매일 1시 0분부터 30분까지 매분 tesh.sh 를 실행
0-30 1 * * * /home/script/test.sh

4.5. 간격 실행

# 매 10분마다 test.sh 를 실행
*/10 * * * * /home/script/test.sh

4.6 조금 복잡하게 실행

# 5일에서 6일까지 2시,3시,4시에 매 10분마다 test.sh 를 실행
*/10 2,3,4 5-6 * * /home/script/test.sh



5. cron 사용 팁

5.1. 한 줄에 하나의 명령만 사용

# 잘못된 예
* * * 5 5
/home/script/test.sh

# 잘된 예
* * * 5 5 /home/script/test.sh

5.2. 주석을 사용 가능

  • # 을 입력해서 그 뒤로 나오는 모든 문자를 주석 처리 가능

    # 주석 #
    #--------------------#
    # 이것은 주석입니다. #
    #--------------------#



6. cron 로깅 (cron logging)

6.1. crontab을 사용할 때 처리 내역을 로그에 남김

  • 크론탭을 사용해서 정기적으로 작업을 처리할 때, 해당 처리 내역에 대해 로그를 남김
  • /home/script/test.sh 쉘 스크립트를 매분마다 실행 → test.sh.log 파일에 작업 내용을 갱신
  • 2>&1 을 제거하면 쉘스크립트에서 표준 출력 내용 출력
  • 2>&1은 표준 에러를 표준 출력
      * * * * * /home/script/test.sh > /home/script/test.sh.log 2>&1

6.2. crontab의 사용에 대한 처리 내역을 지속적으로 로그에 남김

  • 자주 실행 되고 또한 지속적으로 로깅이 되야 해서 로그를 계속 남겨둬야 한다면 다음처럼 입력
  • 계속 로그가 누적이 되는 것을 확인
  • 로그가 과도하게 쌓이면 서비스에 영향 줌 → 가끔씩 비워주거나 파일을 새로 생성 필요
      * * * * * /home/script/test.sh >> /home/script/test.sh.log 2>&1

6.3. crontab에 로그가 필요하지 않아 삭제

  • 로그는 필요 없는 크론을 위해서 /home/script/test.sh.log 파일이 아닌 /dev/null에 저장
      * * * * * /home/script/test.sh > /dev/null 2>&1


7. crontab 백업 (crontab backup)

  • crontab -r 를 쓰거나 실수로 crontab 디렉토리를 날려버려서 기존 크론 내역들이 회복이 불가능할 수 있음
  • 시스템 문제로 또는 실수로 크론탭이 삭제 될 수 있기에 주기적으로 크론탭 백업은 필수

7.1. crontab 백업하는 방법 → crontab 내용을 txt 파일로 만들어 저장

crontab -l > /home/bak/crontab_bak.txt

7.2. crontab 백업하는 방법 → crontab 내용을 txt 파일로 만들어 자동으로 저장

  • 매일 오후 11시 50분에 크론탭을 백업해두는 크론 명령어
    50 23 * * * crontab -l > /home/bak/crontab_bak.txt

1. OMSA 시작

$ /opt/dell/srvadmin/sbin/srvadmin-services.sh start

2. OMSA 멈춤

$ /opt/dell/srvadmin/sbin/srvadmin-services.sh stop

3. OMSA 재시작

$ /opt/dell/srvadmin/sbin/srvadmin-services.sh restart

4. OMSA 상태 확인

$ /opt/dell/srvadmin/sbin/srvadmin-services.sh status

5. OMSA 런레벨 2, 3, 5에서 enable 설정

$ /opt/dell/srvadmin/sbin/srvadmin-services.sh enable

6. OMSA 런레벨 2, 3, 5에서 disable 설정

$ /opt/dell/srvadmin/sbin/srvadmin-services.sh disable

7. OMSA가 실행 중인지 체크

$ /opt/dell/srvadmin/sbin/srvadmin-services.sh is-enabled
instsvcdrv: enabled
dsm_sa_datamgrd: enabled
dsm_sa_eventmgrd: enabled
dsm_sa_snmpd: enabled
dsm_om_connsvc: enabled

작업 예약 스케줄러 파일인 cron

  • 특정한 시간에 또는 특정 시간마다 어떤 작업을 자동으로 수행하게 해주고 싶을 때 사용하는 명령어
  • cron은 특정한 시간에 특정한 작업을 수행하게 해주는 스케줄링 역할

1. 시스템 크론(system cron)

  • cron 시스템에는 시스템에서 기본적으로 사용하는 cron 설정
  • 시스템 운영에 필요한 작업은 root 권한으로 /etc/crontab에 등록해서 주기적으로 수행 가능

2. 사용자 크론(user cron)

  • root나 일반 사용자가 자신의 cron 설정을 직접하여 사용
  • 사용자는 crontab이라는 명령을 수행해서 등록


cron과 관련된 여러 파일들

1. cron

  • /usr/sbin/cron → 크론 데몬 파일

2. crontab

  • cron 작업을 설정하는 파일 → crontab 파일
  • cron 프로세스는 /etc/crontab 파일에 설정된 값을 읽어서 수행
  • crontab 파일은 OS에 따라 저장되는 위치가 다를 수 있음
  • crontab의 파일 내용
    1. m h dom mon dow user command
    2. 분 시 일 월 요일 사용자 실행명령 → crontab의 형식
    3. *의 의미는 every
    4. 25 6 * * * root test -x /usr/sbin/anacron ~
    5. 6시 26분마다 root 사용자가 test -x /usr/sbin/anacron ~ 명령 실행

3. /usr/sbin/anacron

  • cron과 비슷한 동작을 할 수 있게하는 프로그램
  • 서버가 일정 시간 중지되었을 때에도 작업이 실행되는 것을 보장하기 위해 사용하는 도구

4. /etc/cron.daily, /etc/cron.hourly, /etc/cron.weekly, /etc/cron.monthly

  • 시스템 크론 설정 디렉토리
  • cron은 주기적으로 실행할 내용을 시스템 크론 설정 디렉토리에 넣어 놓고 작동

5. /var/log/cron

  • 크론 실행 내용이 기록되는 로그 파일

6. /etc/cron.allow, /etc/cron.deny

  • 크론 접근을 허용할 ID, 크론 접근을 허용하지 않을 ID 등을 설정


cron 동작 방식, cron 실행 흐름

  • cron 동작 방식을 보면 cron 데몬(crond)가 crontab을 참조
  • cron 데몬은 어떤 task를 언제 어떻게 수행할 지를 crontab에서 찾아서 실행
  • cron 데몬은 시스템 스케줄러 정보 뿐만 아니라 각각 사용자가 설정한 작업 예약 정보도 crontab에서 확인
  • cron 파일이 데몬이기 때문에 부팅시 백그라운드로 실행
    $ ps -ef | grep cron

crontab 설정 형식(crontab 파일의 7 필드)

  • m h dom mon dow user command 설명

crontab 설정 값에 사용할 기호

1. * (별표)

  • 각 필드 자리에 * 기호가 오면 해당 필드의 모든 값을 의미
  • 두 번째 필드에 *가 오면 매 시간 마다
  • 세 번째 필드에 *가 오면 매일
  • 네 번째 필드에 *가 오면 매월

2. - (하이픈)

  • 그 사이의 모든값을 의미
  • 세 번째 필드에 '1-5' 값이 오면 1일, 2일, 3일, 4일, 5일 의미

3. , (쉼표)

  • 지정한 모든 값을 의미
  • 불규칙적인 값 지정할 때 주로 사용
  • 두 번째 필드에서 "1,3,4"는 1시, 3시, 4시를 의미

4. / (슬래시)

  • 연결된 설정 값 범위에서 특정 주기로 나눌 때 사용

Content-Length: 엔터티의 길이

  • Content-Length 헤더는 메시지의 엔터티 본문의 크기를 바이트 단위
  • 어떻게 인코딩 되었든 상관없이 크기를 표현
  • Content-Length 헤더는 메시지를 청크 인코딩으로 전송하지 않는 이상, 엔터티 본문을 포함한 메시지에서는 필수적으로 있어야 함
  • 서버 충돌로 인한 메시지 잘림 검출과 지속 커넥션을 공유하는 메시지를 분할하고자 할 때 필요

1. 잘림 검출

  • 오래된 버전의 HTTP는 커넥션이 닫힌 것을 보고 메시지가 끝났음을 인지
  • Content-Length가 없다면 커넥션이 정상적으로 닫힌 것인지 구분하지 못함
  • 메시지 잘림은 캐싱 프록시 서버에서 특히 취약
  • 캐시가 잘린 메시지를 수신했으나 잘렸다는 것을 인삭하지 못했다면, 캐시는 결함이 있는 컨텐츠를 저장하고 계속해서 제공.
  • 결함있는 컨텐츠를 제공하는 것을 방지하기 위하여, 캐싱 프록시 서버는 명시적으로 Content-Length 헤더를 갖고 있지 않은 HTTP 본문은 캐시하지 않음

2. 잘못된 Content-Length

  • Content-Length가 잘못된 값을 담고 있을 경우 아예 빠진 것보다도 큰 피해를 유발함
  • HTTP/1.1에서는 사용자 에이전트가 잘못된 길이를 받고 이를 인지했을 때, 사용자에게 알려주게 됨

3. Content-Length와 지속커넥션

  • Content-Length는 지속 커넥션을 위해 필수
  • 클라이언트에게 메시지 하나가 어디서 끝나고, 다음 시작은 어디인지 알려줌
  • 커넥션은 지속적이기에, 클라이언트가 커넥션이 닫힌 위치를 근거로 메시지의 끝을 인식하는 것은 불가능
  • HTTP 애플리케이션은 엔터티 본문의 길이와 끝을 인식하고자 Content-Length 헤더를 활용
  • 청크 인코딩을 사용하는 경우는 예외
  • 청크 인코딩은 데이터를 특정 크기를 갖는 청크들로 쪼개어 보내며, Content-Legnth 헤더를 필요로 하지 않음


컨텐츠 인코딩

  • HTTP는 보안을 강화하거나 압축을 통해 공간을 절약할 수 있도록, 엔터티 본문을 인코딩할 수 있게 해줌
  • 만약 본문의 컨텐츠가 인코딩되어 있다면, Content-Length 헤더는 원본이 아닌 인코딩된 본문을 바이트 단위로 정의함
  • HTTP/1.1 명세에서 어떤 헤더도 인코딩 전 원본의 길이를 보내고자 사용되지 않음
  • 클라이언트가 수행한 디코딩 과정의 검증을 어려움
  • Content-MD5 헤더도 인코딩된 문서의 MD5를 담음 → 자주 사용 X

  • 문자셋(Character set) : 문자 코드 집합
  • 인코딩(Encoding) : 문자 코드 집합을 표현하는 방법 → 인코딩 방법은 문자셋에 종속적임

1. 인코딩(Encoding)

  • 컴퓨터 안에서는 문자든 숫자든 모두 숫자(‘01010001110011…’)로 나타냄
  • 일반적으로 우리가 사용하는 언어(텍스트)를 기계가 이해하는 언어로 표현하는 방법을 인코딩(encoding)
  • ASCII 코드는 미국에서 만든 최초의 문자열 인코딩 방법
    1. 대문자 A → 65로 ASCII 코드 표시
    2. 소문자 a → 97로 ASCII 코드 표시
  • 영어, 중국어, 프랑스어 등 많은 언어마다 인코딩의 방법이 다름
  • 한글을 기계가 이해시키는 인코딩 방법 → 여러개가 있는데 그 중 가장 많이 사용되는 것이 CP949와 UTF-8(Unicode).


2. ksc5601과 cp949

  • ksc5601과 cp949은 문자셋이기는하나, 각각 조금은 다른 인코딩 방법

2.1. ksc5601

  • 92년도에 국가에서 정의한 표준으로 2바이트를 사용
  • 한글 2,350자 표현 가능
  • 전각문자/기호/자소/선문자 0xA180 ~ 0xAFFF
  • 한글영역 0xB0A1 ~ 0xC9FF
  • 한자영역 0xCA80 ~ 0xFDFF

2.2. cp949

  • cp949는 윈도95에 마이크로소프트가 독자적으로 제정한 규격
  • 한글 11,172자 표현 가능
  • cp949 인코딩은 확장된 euc-kr임 → 기존의 euc-kr에 추가적으로 지원하는 문자셋을 덧붙인 형태
  • 현재는 윈도우가 유니코드도 지원하며, 요즘 개발되는 윈도우는 유니코드를 베이스 사용

2.3. windows, linux, java, web 정리 → 최근은 Unicode를 사용하기에 큰 의미는 없지만 혹시나 정리

  • html 문서에 charset=cp949 등으로 지정된 웹페이지가 있기는 한데, 이것은 엄연히 표준을 위반
  • W3C에서는 IANA에서 공인된 문자셋만을 표준 → CP949 혹은 MS949은 포함 X
  • java에서 ksc5601가 cp949로 표시되는 지 모름, cp949는 또 ms949로 표현
  • 윈도우는 CP949방식을 사용
  • 윈도우를 개발한 마이크로 소프트에서 EUC-KR 방식에서 확장 → MS949



3. 유니코드(Unicode)

3.1. 한글의 문자 집합

  • 문자를 표현하기 위해서 가장 먼저 ‘문자 집합’을 정의 필요
  • 문자 집합은 표현해야 할 문자를 정하고 순서를 지정
  • 예시
    1. 한글 표현 방법 중 조합형 : 한글의 원리에 기반하여 초성, 중성, 종성에 각각 코드를 할당하는 방식
    2. 한글 표현 방법 중 완성형 : ‘가’,’각’,’간’과같이 완성된 문자에 코드를 할당하는 방식으로, 한글 표준안
    3. 영어: ‘A’ ~ ‘z’ (대문자에서 소문자까지)
    4. CCS(coded character set) : 문자 집합을 행렬로 표기한 형태
    5. CES(character encoding scheme) : 문자 집합을 컴퓨터에 저장하기 위해서 8비트 단위 형태로 표현한 인코딩 방식

3.2. 유니코드

  • 각 나라 언어에는 컴퓨터에서 해당 언어를 표현할 수 있는 독자적인 문자 집합이 있음
  • 하나의 문자 집합을 사용하는 문서에서는 다개국어를 동시에 표현 X
  • 유럽어의 문자도 마찬가지로 같은 문자지만 문자집합에 따라 코드가 다름
  • 전 세계적으로 사용되는 모든 문자 집합을 하나로 모아 탄생시킨 것이 유니코드.

3.3. 유니코드 인코딩 방식

  • 문자 인코딩은 문자들의 집합을 부호화(정보의 형태나 형식을 변환하는 처리)하는 방법
  • 유니코드의 인코딩 방식
  • 코드 포인트를 코드화한 UCS-2와 UCS-4
  • 변환 인코딩 형식(UTF, UCS Transformation Format)인 UTF-7, UTF-8, UTF-16, UTF-32
  • 위 인코딩 방식 중에 ASCII와 호환이 가능하면서 유니코드를 표현할 수 있는 UTF-8 인코딩이 가장 많이 사용

3.4. 코드포인트

  • 유니코드의 값을 나타내기위해서는 코드포인트를 사용 → 보통 U+를 붙여 표시
  • A의 유니코드 값 표기 방법 (아래 2가지 중 1가지 방법으로 표시)
    1. U+0041
    2. \u0041
  • U+1100~U+11FF 사이에 한글 자모 영역
  • U+AC00~U+D7AF 사이에 한글 소리 마디 영역

3.5. 유니코드 범위 목록에서 한글 관련 범위

3.6. 한글표현의 대표적 두 개의 코드영역

  • 한글 소리 마디와 한글자모, 한글 자모 확장 이렇게 두 개의 코드 영역이 있다는 것은 같은 글자를 표현하는 서로 다른 두 개의 방법이 있음
  • 같은 ‘가’의 글자여도, 표현법에 따라 코드 값이 다름
  • 한글 자모, 한글 자모 확장
    • 초성/종성을 구별하는 자음과 모음으로 구성
    • 완성(조합 전) 문자 하나하나에 코드 매칭
    • 이를 이용하여 조합형 한글을 표현할 수 있음
    • 한글 자모 영역에는 옛한글에서만 사용된 초성, 중성, 종성이 있으므로, 옛한글을 표현할 수 있음
    • U+1100부터 U+115E까지는 초성, U+1161부터 U+11A7까지는 중성, U+11A8부터 U+11FF까지는 종성

3.7. 유니코드 정규화(Unicode equivalence)

  • 유니코드 정규화(Unicode equivalence)란 연속적인 코드를 사용하여 표현한 어떤 글자를 처리하는 방법
  • 프로그래밍 언어의 유니코드 정규화 기능을 사용하여 문자열을 분석 가능
  • 다양한 인코딩 방식이 있기에 환경에 따라서 다른 인코딩을 만날 수 있음
  • 웹의 경우에 어딘가에서 한글이 깨진다면, 그 이유는 브라우저 인코딩 값과 서버 인코딩 값이 다른 이유
  • 웹에서 여러 인코딩을 지원하려면, 인코딩된 URL 문자열과 사용한 인코딩 정보를 파라미터로 전달

4. 인코딩 간의 문제점 → 인코딩방식에 따라 표기할 수 있는 관계

  • 완성형 중에서 EUC-KR의 경우, 빠져있는 문자가 있어 모든 문자를 표현 불가능 → 웹을 사용하지 않는 윈도우 환경에서는 불편함 X
  • 확장 완성형인 CP949의 경우에는 유니코드(UTF-8)에서 표현할 수 있는 모든 문자를 표현 가능
  • 웹에서의 UTF-8이면 UTF-8, EUC-KR이면 EUC-KR끼리 밖에 제대로 표현 X →각종 웹 소스들을 사용할 때 인코딩 부분 해결해야함
  • 웹에서 인코딩을 변환하도록 하는 함수도 있고, 서버 자체의 인코딩을 바꾸는 방법도 있음
  • 환경마다 가지고 있는 문제들이 제각각이기 때문에, 한글 부분에 문제가 발생하면 인코딩을 먼저 확인 필요

  • 일반적으로 FTP 서버를 이용한 파일 전송은 보안 기능이 적용 X
  • 안전한 파일 전송을 위해 사용하는 가장 일반적인 방법 → SFTP와 FTPS를 사용

SFTP

  • SFTP는 암호화된 SSH 연결을 이용
  • SFTP는 서버 접속, 파일 전송, 그리고 파일 관리를 지원하기 위해 IETF(Internet Engineering Task Force)에서 개발한 네트워크 프로토콜
  • SFTP를 사용하기 위해선 SSH2 프로그램을 설치한 후에 활성화 필요

SFTP의 특징

  1. 안전한 파일 전송
    • SFTP는 안전한 파일 전송을 위해 SSH로 연결을 암호화
  1. 안전한 FTP 서버 접속
    • 안전한 서버 접속을 위해 인증 방법으로서 패스워드 뿐만 아니라 공개키(Public Key)를 이용한 접속을 지원
  1. 대부분의 플랫폼에서 사용 가능
    • SFTP는 Windows, Unix, linux 등 대부분의 플랫폼에서 지원
  1. SSH 서버가 제공하는 프로그램 (VSFTP 서버와 별개)
    • VSFTP 서버와 별개의 프로그램이지만, 안전한 파일 전송을 지원한다는 점에서 FTP와 동일한 역할

SFTP 서버 설정

1. OpenSSH 패키지 다운

  • sftp 명령어를 사용하려면 SSH 패키지가 필요
  • OpenSSH 패키지를 설치하면 SSH 패키지를 설치 가능
    $ yum install openssh-server openssh -y

2. SSH 서버의 설정 파일 변경

  • /etc/ssh/sshd_confg 파일을 수정

  • 기존에 있던 설정을 internal-sftp로 변경 (아래에 설명)

    $ vi /etc/ssh/sshd_config
    
    # 기존에 있던 Subsystem을 주석처리하고 새로운 Subsystem을 추가
    # override default of no subsystems
    # Subsystem     sftp    /usr/libexec/openssh/sftp-server
    Subsystem       sftp    internal-sftp
    
    # Example of overriding settings on a per-user basis
    Match User sftp-users
        X11Forwarding no
        AllowTcpForwarding no
    #  ChrootDirectory /home/%u
        ForceCommand internal-sftp

3. /etc/ssh/sshd_config 파일 내 적용 요소 설명

  1. #Subsystem sftp /usr/libexec/openssh/sftp-server
    • 서브시스템으로 사용되던 기존 sftp 프로그램을 사용 X → 앞에 주석 추가
  1. Subsystem sftp internal-sftp
    • SSH 서버에서 외부 프로그램을 사용
    • 키워드 Subsystem에 이름 sftp와 명령어 internal-sftp를 지정
    • internal-sftp는 Match Group sftp-users의 ChrootDirectory 옵션을 사용해 각 사용자 별로 chroot를 적용하기 위해 sftp-server 대신 사용
  1. Match Group sftp-users
    • sftp를 사용할 그룹 이름과 옵션을 정의
    • 그룹 안에 속한 사용자들은 ssh 및 scp를 사용 불가능 → 오직 sftp만 사용 가능
      1. X11Forwarding no → ssh 접속해서 GUI 기반의 어플리케이션 실행 X
      2. AllowTcpForwarding no → TCP 포워딩을 불가능
    • chroot를 적용돼 자신의 홈 디렉토리를 루트(/) 디렉토리로 인식
      1. ChrootDirectory는 root로 적용될 디렉토리 위치를 지정
      2. %u → 인증된 사용자의 사용자 이름을 지정
    • ForceCommand internal-sftp → internal-sftp를 강제 명령으로 실행

4. 그룹 생성 및 그룹에 사용자 포함

  • SFTP 사용이 적용될 그룹 sftp-users를 생성하기 위해 명령어 groupadd를 사용

  • 그룹을 만든 후 사용자를 그룹에 포함 → 예시 : hippo 사용자

  • hippo 사용자의 홈디렉토리에 그룹 회원들이 접속할 수 있도록 권한을 변경

    # 변경한 /etc/ssh/sshd_config을 새로 적용
    $ systemctl restart sshd
    
    # sftp-users 그룹 생성
    $ groupadd sftp-users
    
    # sftp-users 그룹에 root 사용자를 추가
    # usermod -g sftp-users root를 하면 그룹 하나만 속함 -> 사용 X
    $ usermod -aG sftp-users root
    $ id root
    uid=0(root) gid=0(root) groups=0(root),10(wheel),1000(sftp-users)
    
    # hippo 사용자가 없기에 새로 추가 필요
    $ id hippo
    id: hippo: no such user
    
    # hippo 사용자 추가
    $ adduser hippo
    $ passwd hippo
    
    # sftp-users에 hippo 사용자 추가
    $ usermod -aG sftp-users hippo
    
    # hippo 사용자가 정상적으로 생성되고 sftp-users에 들어있는 지 확인
    # wheel 그룹에 속하려면 /etc/group의 wheel에 hippo를 추가해야 함
    $ id hippo
    uid=1000(hippo) gid=1001(hippo) groups=1001(hippo),10(wheel),1000(sftp-users)
    
    # 권한 변경
    $ chmod 755 /home/hippo
    
    $ ls -al /home
    drwxr-xr-x   2 hippo hippo 4096 Jan 30 21:54 hippo

리눅스 SFTP 클라이언트 테스트

  • 접속하는 윈도우 SFTP 클라이언트

  • 리눅스 클라이언트로 이용하여 테스트

  • 리눅스 SFTP 접속 → IP 접속을 허용해줘야 함 (ACL 정책 확인 필요)

    $ sftp -P 22000 root@[서버 IP] 
    root@[서버 IP]'s password: 
    Connected to [서버 IP]. 
    
    # SFTP 접속 위치의 파일 확인 
    sftp> ls 
    test.sh   time 
    
    # SFTP 현재 위치 확인 
    sftp> pwd 
    Remote working directory: /root 
    
    # SFTP 접속 해제 
    sftp> exit`

+ Recent posts