정보보안핵심 · 19분 읽기

TLS: 인증된 통신 경로 만들기

TLS는 전송 중 기밀성과 무결성을 제공하고 통신 상대를 인증하는 데 쓰인다. 핸드셰이크의 인증·키 합의와 실제 데이터 암호화를 구분해 이해한다.

개념부터 찾아보기

정의·역할·동작 원리를 독립 페이지에서 확인하세요. 본문의 밑줄 용어에도 설명이 있습니다.

이 노트에서 설명할 수 있게 되는 것

  1. TLS 1.3의 평문 메시지와 암호화된 메시지 경계를 표시한다.
  2. 인증서·CertificateVerify·Finished의 목적을 구분한다.
  3. 키 합의부터 애플리케이션 키 도출까지 상태 변화를 설명한다.

01개념과 구성 요소

  • 는 통신 상대의 인증, 전송 기밀성, 전송 중 변조 검증을 제공한다.
  • 인증서·서명은 상대 인증, 임시 키 합의는 공유 비밀 생성, 는 레코드 보호를 담당한다.
  • 아래 순서는 ··클라이언트 인증이 없는 전체 핸드셰이크다.

02TLS 1.3 전체 핸드셰이크의 메시지 순서

  1. 클라이언트가 지원 버전·스위트·그룹·서명 방식과 를 보낸다.
  2. 서버가 선택 결과와 를 보낸다. 양쪽은 임시 공유 비밀과 문맥으로 방향별 핸드셰이크 키를 도출한다.
  3. 서버가 EncryptedExtensions와 Certificate를 핸드셰이크 키로 보호해 보낸다. 클라이언트는 이름·인증서 경로를 검증한다.
  4. 서명으로 개인키 소유를 확인하고 로 공유 비밀·누적 핸드셰이크 문맥의 일치를 검증한다.
  5. 클라이언트가 자신의 를 보내고 서버가 검증한다. mTLS나 재개 연결은 이 기본 메시지 흐름과 다르다.
  6. 별도 트래픽 키와 로 HTTP 등을 보호한다. 서버 데이터는 허용된 상태에서 클라이언트 보다 먼저 전송될 수도 있다.

03TLS에서 인증·키 합의·레코드 보호는 다른 일이다

  • 는 연결 상대의 인증, 전송 중 기밀성, 전송 중 변조 탐지를 결합한다. HTTPS는 이 보호된 경로 위에서 HTTP를 전달하는 사용 방식이다.
  • 인증서의 공개키로 모든 HTTP 본문을 계속 암호화하는 구조가 아니다. 현대적인 인증서 기반 연결에서는 인증서 키가 상대 인증에 사용되고, 임시 키 합의로 만든 비밀에서 대칭 트래픽 키를 도출한다.
  • 기본 흐름은 ··클라이언트 인증이 없는 전체 핸드셰이크다. 세션 재개와 mTLS에서는 메시지가 추가되거나 생략된다.
  • 또한 패킷, 레코드, 핸드셰이크 메시지는 서로 다른 경계다. 하나의 메시지가 여러 세그먼트로 나뉘거나 여러 메시지가 한 세그먼트에 실릴 수 있다.

04ClientHello: 지원 목록과 임시 공개값을 제시한다

  • 클라이언트는 지원 버전, 암호 스위트, 랜덤 값, 지원 그룹과 , 서명 알고리즘 등 협상 재료를 보낸다. SNI는 같은 서버 주소에서 어떤 서비스 이름으로 접속하는지 알리는 확장이고 ALPN은 HTTP/2 같은 상위 프로토콜을 협상하는 확장이다.
  • 단순히 서버 포트에 연결했다고 사용할 버전과 인증 방식이 정해지는 것은 아니다.
  • 의 TLS_AES_128_GCM_SHA256 같은 스위트 이름은 레코드 보호용 와 키 스케줄에 사용하는 해시를 나타낸다. 서버 인증서가 인지 ECDSA인지, 어떤 ECDHE 그룹을 쓸지는 별도 협상 정보다.
  • 초기 는 일반적인 에서 평문 관찰 대상이므로 본문이 암호화되어도 모든 접속 메타데이터가 자동으로 숨겨지는 것은 아니다.

05ServerHello와 키 공유: 같은 비밀을 각자 계산한다

  • 서버는 제안된 범위에서 선택 결과와 서버 를 보낸다. 각 참여자는 자기 임시 개인값과 상대 공개값으로 공유 비밀을 계산한다.
  • 양쪽이 같은 결과에 도달하지만 세션 키 자체를 패킷에 싣는 것은 아니다. 제안한 키 공유가 적절하지 않은 경우 HelloRetryRequest로 다른 조건의 재시도를 요청하는 경로도 있어 항상 왕복 횟수가 동일하지는 않다.
  • 기반 키 스케줄은 공유 비밀과 핸드셰이크 메시지의 해시 문맥을 사용하여 용도별 비밀을 만든다. 핸드셰이크 트래픽 비밀과 애플리케이션 트래픽 비밀, 클라이언트 방향과 서버 방향은 구분된다.
  • 동일 공유 비밀을 그대로 양방향 키로 사용하는 그림은 이 분리를 생략한 것이다.

06ServerHello 뒤에 암호화 경계가 생긴다

  • 두 Hello를 통해 핸드셰이크 키를 도출하면 서버의 EncryptedExtensions, Certificate, , 는 그 단계의 키로 보호된다.
  • EncryptedExtensions에는 에 실리지 않는 추가 협상 결과가 들어가며 ALPN 선택도 대표적인 예다. 따라서 수동 PCAP에서 뒤에 암호문이 보인다고 즉시 HTTP 데이터가 시작됐다고 단정할 수 없다.
  • 에서는 서버 인증서 내용도 이 암호화된 구간에 속한다. 패킷만 가진 제3자가 언제나 인증서의 SAN과 전체 HTTP를 읽을 수 있는 것은 아니다.
  • endpoint의 세션 비밀을 사용하는 허가된 분석이나 종료 지점의 관찰은 추가 조건을 가진 별도 상황이다. 원본 그림의 녹색 메시지는 바로 이 경계를 학습하기 위한 표시다.
수업 원본 자료

원본에서 읽는 TLS 1.3 암호화 경계

원본에서 읽는 TLS 1.3 암호화 경계원본 크기로 보기 ↗
수업 원본 학습도 · 인증서 기반 전체 핸드셰이크를 설명한다. PSK·0-RTT·mTLS·HelloRetryRequest와 세부 레코드 경계는 생략된 그림이다.

이 자료에서 읽어낼 것

  1. ClientHello·ServerHello 뒤에 Handshake 키 생성이 놓인다. 이후 녹색 서버 메시지에는 인증서도 포함된다.
  2. CertificateVerify는 개인키 소유 증명, Finished는 합의된 비밀과 핸드셰이크 문맥 확인으로 구분되어 있다.
  3. 맨 아래 애플리케이션 화살표는 개념상 묶은 표시다. 화살표 하나가 TCP 패킷 하나라는 뜻은 아니다.

07Certificate: 키를 이름과 신뢰 경로에 묶는다

  • 서버는 리프 인증서와 필요한 중간 CA 인증서를 전달한다. 클라이언트는 인증서 서명 경로를 로컬 신뢰 기준에 연결하고, 요청한 이름과 SAN, 유효기간, 용도와 경로 제약을 평가한다.
  • 루트 인증서를 서버가 함께 보낸다는 사실만으로 새로운 루트를 신뢰해서는 안 된다.
  • 이 단계가 성공하면 공개키와 서비스 이름을 연결할 수 있지만 현재 연결 상대의 개인키 소유 증명은 아직 별도로 필요하다. 유효한 인증서 파일은 누구나 복사할 수 있기 때문이다.
  • 인증서 체인을 보냈다는 사실과 이번 핸드셰이크의 키 합의가 인증되었다는 결론을 구분해야 다음 메시지의 의미가 보인다.

08CertificateVerify와 Finished가 증명하는 차이

  • 는 서명 알고리즘이 정한 문맥과 지금까지의 핸드셰이크 해시를 개인키로 서명한다. 클라이언트는 인증서 안의 공개키로 검증하여 연결 상대가 대응 개인키를 가졌고 이번 협상 문맥에 참여했음을 확인한다.
  • 단순히 인증서를 복사한 중간자는 이 서명을 정상적으로 만들 수 없다.
  • 는 핸드셰이크 비밀로부터 도출된 키와 누적 메시지 해시에 기반한 검증값이다. 서명을 다시 한 번 보내는 메시지가 아니라 키 합의와 핸드셰이크 문맥에 대한 확인이다.
  • 클라이언트는 서버 를 검증하고 자신의 를 보내며 서버도 이를 검증한다. Hello 메시지의 협상 내용이 중간에서 바뀌면 양쪽이 같은 문맥을 계산하지 못해 검증이 실패할 수 있다.

09애플리케이션 레코드와 태그 검증

  • 애플리케이션 트래픽 키는 핸드셰이크 보호 키와 구분해 도출된다. HTTP 요청·응답은 레코드 계층에서 로 보호되고 수신자는 태그 검증이 성공한 데이터만 상위 계층에 전달한다.
  • 방향마다 다른 키와 레코드 순서 문맥을 사용하므로 반대 방향에서 본 암호문을 그대로 가져와 정상 요청처럼 처리하는 구조가 아니다.
  • 서버는 허용되는 핸드셰이크 상태에서 클라이언트의 최종 메시지 전에도 애플리케이션 데이터를 보낼 수 있는 경우가 있다. 입문 흐름도에서 모든 애플리케이션 화살표를 맨 아래에 묶는 것은 전체 절차를 단순화한 표현이다.
  • 도식의 화살표 하나를 패킷 하나나 모든 구현의 정확한 송신 시점으로 해석하지 않는다.
원리 심화

10TLS 1.3 레코드의 내부 평문과 Nonce

  • TLSInnerPlaintext는 실제 content, 1바이트 content type, 선택적 0 패딩으로 구성된다. 실제 유형도 암호화 구간 안에 있다.
  • TLSCiphertext의 외부 유형은 application_data이며 legacy_record_version은 0x0303이다. 이 값만 보고 1.2라고 판정하지 않는다.
  • 외부 유형·버전·길이를 연결한 5바이트 헤더가 의 additional data에 들어가므로 암호화되지 않아도 인증된다.
  • 방향별 레코드 순서 번호를 IV 길이에 맞춰 0으로 채운 값과 write IV를 XOR해 를 만든다.
  • 송수신 방향과 키 세대마다 상태를 구분한다. 키를 바꾸면 해당 방향의 순서 번호도 0에서 다시 시작하며, 다른 세대의 키·순서 번호를 섞으면 검증에 실패한다.
예제로 추적

11100바이트 내용의 가상 TLS 레코드 길이

  1. 의 16바이트 태그를 사용하고 content는 100바이트, 추가 패딩은 없다고 가정한다.
  2. Content 100바이트와 실제 유형 1바이트를 합쳐 입력 평문은 101바이트다.
  3. 암호문과 태그는 101+16=117바이트이며 외부 length 필드는 이 값을 표현한다.
  4. 헤더 5바이트를 더하면 레코드는 122바이트다. ·IP· 오버헤드는 포함하지 않은 계산이다.
  5. PCAP의 세그먼트 하나가 반드시 122바이트인 것은 아니다. 분할·병합·추가 레코드 때문에 경계가 달라질 수 있다.
검증·예외

12복호화·Finished 오류를 구분하는 증거

  • · 실패는 서로 다른 키와 입력을 검증한다. 인증서 경로 오류와 누적 메시지 불일치를 분리한다.
  • 실패는 키··헤더 AAD·암호문의 조합이 맞지 않다는 뜻이다. 악의적 변조 외에 잘못된 세션 비밀·누락 레코드도 분석 실패 원인이다.
  • 클라이언트·서버의 트래픽 키를 뒤집거나 KeyUpdate 이후에도 이전 키를 적용하지 않았는지 확인한다.
  • RFC의 bad_record_mac 종료와 애플리케이션 HTTP 오류는 다른 계층이다. 가 성립한 뒤 403을 받은 것을 암호 복호화 실패로 기록하지 않는다.

13Forward Secrecy는 장기 인증키와 임시키를 분리한 결과다

  • ECDHE 같은 임시 키 합의는 연결마다 다른 비밀 재료를 사용한다. 공격자가 트래픽을 기록한 후 서버의 장기 인증 개인키를 얻더라도 그 키만으로 과거 연결의 임시 공유 비밀을 바로 계산할 수 없게 하는 성질이 Forward Secrecy다.
  • 그래서 인증서 개인키와 트래픽 키의 역할을 분리해서 이해해야 한다.
  • 이는 모든 형태의 유출을 막는다는 뜻은 아니다. 실행 중 메모리에서 해당 세션 비밀이 탈취되거나 endpoint가 이미 침해되면 별개의 문제가 생긴다.
  • 는 애플리케이션 내부 권한 오류, 저장된 비밀번호, 이미 복호화된 서버 메모리까지 자동으로 보호하는 경계가 아니다.

14TLS 1.2와 1.3을 비교할 때 남겨야 할 조건

  • 1.2는 스위트에 키 교환·인증·대칭 암호·해시 선택이 함께 표현되는 경우가 있고 다양한 과거 선택지를 포함한다. 은 키 합의·서명 협상과 선택을 분리하며 레거시 방식들을 제거하고 더 많은 핸드셰이크 메시지를 암호화한다.
  • 일반적인 전체 연결의 지연 설명에서 1.2의 2-RTT와 1.3의 1-RTT가 비교된다.
  • 이 비교는 연결 시간, 재시도, 세션 재개 등 조건을 생략한 핸드셰이크 비교다. 1.2라는 버전 이름만으로 안전성 전체를 단정할 수 없고 실제 스위트와 인증 검증이 중요하다.
  • 반대로 도 이름 검증을 끈 클라이언트나 유출된 endpoint 비밀을 스스로 해결하지 못한다.

15세션 재개·PSK와 0-RTT의 재생 위험

  • 은 이전 연결에서 얻은 정보로 기반 재개를 할 수 있다. 재개 시의 인증·키 도출 경로는 처음 인증서 교환을 하는 연결과 다르며 와 새로운 키 합의를 결합하는지에 따라 성질도 달라진다.
  • 따라서 “모든 연결은 매번 똑같은 인증서 전체 교환을 한다”는 설명은 맞지 않는다.
  • 는 핸드셰이크 완료 전에 early data를 보낼 수 있게 한다. 지연을 줄이는 대신 정상적인 재전송과 다른 재생(replay) 공격 위험을 고려해야 한다.
  • 한 번만 처리되어야 할 상태 변경이 다시 처리되면 피해가 생기므로 애플리케이션의 요청 의미와 재생 방지 정책이 중요하다. 단순히 암호화되어 있다는 이유로 결제 같은 동작에 무조건 안전하다고 판단하지 않는다.

16mTLS와 인가는 서로 다른 단계다

  • mTLS에서는 서버가 CertificateRequest로 클라이언트 인증서를 요청할 수 있고 클라이언트는 인증서와 개인키 소유를 증명하는 를 전달한다. 서버는 클라이언트 인증서의 신뢰 경로·용도·정책과 서명을 평가한다.
  • 이는 사람이 비밀번호를 입력하는 방식과 다른 인증 증거를 사용하는 것이다.
  • 인증된 서비스나 기기에 어떤 API·문서·관리 기능을 허용할지는 이후 정책이 결정한다. 또한 프록시가 를 종료하면 브라우저→프록시와 프록시→백엔드는 다른 보안 구간이다.
  • 전단의 HTTPS 표시만으로 후단이 암호화되었거나 인증되었다고 판단하지 않는다. 프록시가 전달한 사용자 정보 역시 백엔드가 신뢰할 수 있는 경로에서만 받아야 한다.

17오류 위치를 메시지 상태와 연결하기

  • 공통 버전·스위트가 없으면 Hello 협상 단계에서 진행하지 못한다. 신뢰하지 않는 CA나 이름 불일치는 인증서 검증에, 키 불일치는 서명과 개인키 소유 증명에, 문맥·비밀 불일치는 에 영향을 줄 수 있다.
  • 가 정상적으로 끝난 뒤 HTTP 403이 나온다면 전송 암호화 실패와 애플리케이션 권한 거부를 구분할 수 있다.
  • 원본 캡처에는 와 , 키 생성, 서버 인증 메시지와 양쪽 가 차례대로 표시되어 있다. 이 순서 위에 실제 실패 지점을 놓으면 “SSL 연결이 안 된다”는 현상을 협상·신원·키 확인·업무 처리로 나눌 수 있다.
  • 인증서 갱신 후 일부 경로만 실패하는 상황은 로드밸런서별 인증서와 후단 설정까지 함께 설명한다.

설명과 함께 보는 보조 도식

메시지 순서

모식도 · TLS 1.3의 암호화 경계

인증서 기반 전체 핸드셰이크. PSK·0-RTT·mTLS는 생략했다.

클라이언트서버로컬 신뢰 기준1. ClientHello2. ServerHello3. 인증 메시지와 Finished4. 상대 검증5. Client Finished6. 애플리케이션 데이터
전체 단계를 한 번에 읽기
  1. 01

    ClientHello

    지원 매개변수와 클라이언트 키 공유를 전송한다.

    메시지
    평문
  2. 02

    ServerHello

    선택한 매개변수와 키 공유를 전달하고 핸드셰이크 키를 도출한다.

    다음 메시지
    핸드셰이크 키로 보호
  3. 03

    인증 메시지와 Finished

    EncryptedExtensions·Certificate·CertificateVerify·Finished를 전달한다.

  4. 04

    상대 검증

    체인과 이름, 서명 및 핸드셰이크 검증값을 확인한다.

    검증 실패
    연결 중단
  5. 05

    Client Finished

    클라이언트의 핸드셰이크 검증값을 보낸다.

  6. 06

    애플리케이션 데이터

    용도와 방향별 애플리케이션 트래픽 키로 레코드를 보호한다.

    키
    핸드셰이크 키와 구분
메시지와 상태 변화를 단순화한 학습용 모식도입니다. 생략한 메시지와 예외는 본문의 설명을 함께 확인하세요.
LEARN THROUGH PRACTICE

핸드셰이크의 암호화 경계와 인증 실패 위치 찾기

메시지 순서를 패킷 관찰 가능 범위와 연결하고, 인증서 오류가 발생하는 단계를 설명한다.

실습 구성과 전제

  • 자신의 실습 서버에 정상 HTTPS 연결을 한 번 만들고 PCAP를 저장한다.
  • 전체 핸드셰이크 도해를 기준으로 하되 재개 연결·· 1.2는 별도로 구분한다.
  1. 암호화되기 전 협상 필드를 찾는다

    • 에서 와 의 supported_versions, cipher suite, 를 비교한다. 구버전 호환 필드만 보고 1.2라고 단정하지 않는다.
    • 는 제안, 는 선택 결과다. 양쪽이 합의한 키 공유로 이후 핸드셰이크 보호 키를 도출한다.
    text
    tls.handshake.type == 1 || tls.handshake.type == 2

    표시 필터 예시. 저장된 자신의 실습 PCAP에서 사용한다.

    TLS 1.3 핸드셰이크 · TLS 1.3 Handshake의 전체 흐름원본 크기로 보기 ↗
    • ClientHello와 ServerHello 다음에 'Handshake 암호화 키 생성' 경계가 표시된다.
    • CertificateVerify와 Finished는 서로 다른 메시지로 그려져 있어 키 소유 증명과 핸드셰이크 무결성 확인을 나누어 읽을 수 있다.
    확인 기준

    같은 .stream에서 협상 버전과 키 공유를 확인한다.

  2. 안 보이는 메시지와 실패한 메시지를 구분한다

    • 에서는 뒤의 인증서 메시지도 보통 암호화돼 보인다. 키 로그가 없는 캡처에서 Certificate가 보이지 않는다는 이유만으로 서버가 인증서를 생략했다고 단정하지 않는다.
    • 실습 클라이언트의 브라우저 오류와 패킷 시각을 연결한다. 인증서 경고는 전송 암호화의 유무와 다른 판단이다.
    HTTPS 인증서와 브라우저 표시원본 크기로 보기 ↗
    • HTTPS 주소에서도 CA 신뢰 오류가 표시된다.
    • 경고 화면에는 협상 cipher suite나 Finished 성공 여부가 나타나지 않는다. 이 정보는 패킷·클라이언트 진단으로 보완해야 한다.
    확인 기준

    캡처 가시성 한계와 실제 인증 실패를 보고서에서 분리한다.

  3. 인증 성공 후 애플리케이션 동작을 확인한다

    • 핸드셰이크가 끝나도 HTTP 인가나 로그인 성공이 보장되지는 않는다. 연결 성립→서버 신뢰→애플리케이션 응답을 각각 판정한다.
    • 복호화 가능한 실습 PCAP에서는 정상 요청의 응답을 확인하고, 키 로그 파일은 학습 후 별도로 보호·정리한다.
    확인 기준

    성공과 HTTP 상태 코드를 같은 항목으로 합치지 않는다.

실습에서 확인한 동작 원리

  • 의 암호화 경계는 이후에 생긴다.
  • 신뢰 오류·복호화 자료 부재·애플리케이션 오류는 다른 현상이다.

설정·출력 추가로 확인하기 8장

아래 화면을 펼쳐 위 실습의 설정값, 명령과 확인 기준을 비교해 보세요. 각 묶음은 별도 실습 기록입니다.

실습 화면 묶음 01 2장
0624_보고서 - proxy · 실습·개념 참고 화면 4원본 크기로 보기 ↗
  • 「프록시서버 ←→ 서버 (포트로 클라이언트 매칭)」 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
0624_보고서 - proxy · 패킷 캡처 5원본 크기로 보기 ↗
  • 「프록시서버 ←→ 서버 (포트로 클라이언트 매칭)」 문맥에 삽입된 원본 패킷 캡처이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 02 1장
7/29 · 패킷 캡처 6원본 크기로 보기 ↗
  • 「DVWA Redirect」 문맥에 삽입된 원본 패킷 캡처이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 03 1장
9/17 - HTTPS · 실습·개념 참고 화면 1원본 크기로 보기 ↗
  • 문서 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 04 1장
DVWA 설치 · 실습·개념 참고 화면 1원본 크기로 보기 ↗
  • 문서 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 05 1장
HTTPS 인증서와 브라우저 표시원본 크기로 보기 ↗
  • 학습 원본 · HTTPS 인증서와 브라우저 표시의 HTTPS에 수록된 화면·도식이다.
실습 화면 묶음 06 1장
OWASP - Improper input validacation · 실습·개념 참고 화면 1원본 크기로 보기 ↗
  • 「Improper input validacation」 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 07 1장
pymysql · 실습·개념 참고 화면 3원본 크기로 보기 ↗
  • 「문제 2 ) 주피터 - 네트워크 격리되어있음 (아니었음)」 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
동작·명령 참고 문서
READ · OBSERVE · CONNECT

함께 보는 학습 자료

아래 공식 자료를 본문의 개념·예제와 함께 읽어 보세요. 자료별로 확인할 위치와 관찰할 내용을 적었습니다.

표준

RFC 8448: TLS 1.3의 실제 바이트 추적

3절의 1-RTT 교환에서 메시지 구성·키 도출·레코드 보호가 어떤 순서로 이어지는지 바이트 예와 비교할 수 있다.

읽으면서 확인할 것
  • 메시지 길이와 레코드 길이의 차이
  • 클라이언트·서버 방향별 handshake traffic secret
  • 와 가 등장하는 위치
학습 확인

이해했는지 확인하기

  • 접속 이름과 인증서 SAN·신뢰 경로가 맞는지 확인한다.
  • TLS가 종료되는 지점과 그 뒤 통신 구간을 확인한다.
  • 실제 협상 결과와 인증서 갱신 상태를 점검한다.

함께 확인할 공식 자료