타자 시스템을 남용하다.

12999 단어 javascriptsecurity
JavaScript를 만들기 전에 컴퓨터 프로그램을 작성하는 법을 배웠습니다.당시 학교에서 사용한 언어는 주로 C와 Pascal이었다.그들은 나에게 모든 변수는 정수나 문자열 같은 특정한 유형이 있는데, 이런 유형은 변수에 대해 실행할 수 있는 조작을 결정한다고 말했다.
JavaScript는 조금 다릅니다.

타입
JavaScript에도 유형이 있습니다.변수는 undefinednull와 같은 숫자, 문자열, 부울 값, 객체, 기호 및 특수 값을 가리킬 수 있습니다.

동적 타자
JavaScript 변수는 C 및 Pascal과 달리 라이프 사이클 전체에 다양한 유형의 값을 저장할 수 있습니다.변수는 하나의 실행 장면의 숫자일 수도 있고 다른 실행 장면의 문자열일 수도 있다.이것은 원본 코드를 읽는 것만으로도 프로그램이 어떻게 작동하는지 분석하기 어렵다.

약한 유형
연산자 처리 값.예를 들어, + 연산자는 두 문자열을 더하거나 연결합니다.C 및 Pascal에서는 문자열에 숫자를 추가할 수 없습니다.이 작업은 정의되지 않았으며 변수 중 하나를 다른 유형으로 변환해야 합니다.
JavaScript는 일반적으로 놀라운 방식으로 작업수를 암시적으로 변환하기 위해 최선을 다합니다.

서로 다른 유형의 객체 비교
JavaScript에는 두 개의 비교 연산자가 있습니다.

  • 엄격하게 비교(===) 값과 유형을 동시에 비교한다.비교한 값이 다른 유형이 있으면, 되돌아옵니다. false이것은 우리가 비교 연산자에서 직관적으로 기대한 결과다.

  • 느슨한 비교(==)는 비교를 가능하게 하기 위해 동작 수를 자동으로 유니버설 형식으로 변환하려고 시도한다.전환의 규칙은 매우 복잡해서 초보자를 곤혹스럽게 할 수도 있다.누가 특수치null가 다른 특수치undefined와 같다고 생각합니까?
  • 동적 및 비고정 유형 모두 JavaScript 프로그램을 매우 유연하고 간결하게 만들 수 있지만 보안 문제를 야기할 수도 있습니다.

    동적 지침 기반 검색
    JavaScript의 동적 특성을 사용하면 서로 다른 속성의 객체를 포함하여 다양한 유형의 데이터를 처리하는 알고리즘을 사용할 수 있습니다.
    임의의 필드와 값을 기반으로 그룹의 대상을 검색할 수 있는 HTTP 단점을 실현하고, 유형 시스템이 코드를 최대한 통용할 수 있도록 도와주는 방법을 알아보겠습니다.이것은 서로 다른 유형의 대상과 서로 다른 유형의 검색 필드에서 그것을 다시 사용하는 데 도움을 줄 것입니다.
    우리의 예는 HTTP 요청을 처리하는 세부 사항을 처리하기 위해 Express framework를 사용하지만, 코드를 이해하기 위해 익스프레스를 깊이 이해할 필요는 없습니다.

    검색 예
    우리의 예시에서, 우리는 사용자를 대표하는 대상 그룹을 검색할 것이다.검색 매개 변수는 검색 문자열 매개 변수로 전달됩니다.호출자는 field 매개 변수에서 대상 속성 이름을 전달하고 value 매개 변수에서 검색 값을 전달합니다.이렇게 하면 한 단점이 여러 개의 다른 검색 조건을 지원할 수 있다.
    예제 HTTP 요청 및 응답은 다음과 같습니다.
    GET /profile?field=email&value=joe%40wiredbraincoffee.com HTTP/1.1
    Host: localhost:3000
    Connection: keep-alive
    Accept: */*
    
    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Content-Length: 120
    Connection: keep-alive
    
    [{"email":"[email protected]","password":"coldbrew","address":"1235 Wired Brain Blvd\r\nAwesome City, MM 55555"}]
    

    처리자
    HTTP 프로세서 코드는 매우 일반적입니다.
    const users = require('./users');
    
    function readProfile(req, res) {
        // Get search params
        const [field, value] = getParams(req.query, ['field', 'value']);
        // Find user(s)
        const results = filter(users, field, value);
        res.json(results);
    }
    
    먼저 별도의 모듈users 어레이를 가져옵니다.함수readProfile는 검색 알고리즘을 실현하고 HTTP 요청과 응답 대상을 매개 변수로 하는 Express 약정에 부합한다.
    흥미로운 것은 여기서부터 시작된다. 우리는 fieldvalue 검색 문자열 파라미터의 값을 가져오고, 이 값 검색 users 의 그룹을 사용하여 속성이 field 변수에 저장되고 값이value 변수와 같은 대상을 찾는다.

    효용 함수readProfile 구현은 간단해 보이지만 대부분의 작업은 filter 함수에서 발생한다.
    // Return items where a field has specific value
    function filter(items, field, value) {
        const results = [];
        for (let i = 0; i < items.length; ++i) {
            if (items[i][field] == value) {
                results.push(items[i]);
            }
        }
        return results;
    }
    
    filter 함수 교체 수조의 모든 요소를 괄호 표시법으로 이름으로 대상 속성을 검색합니다.이 알고리즘은 느슨한 비교 연산자를 사용하여 대상 속성 값을 사용자가 제공한 검색 조건과 비교한다.
    // Retrieve array of parameters from the query string
    function getParams(qs, params) {
        const results = [];
        for (let i = 0; i < params.length; ++i) {
            const value = qs.hasOwnProperty(params[i])
                ? qs[params[i]]
                : null;
            results.push(value);
        }
        return results;
    }
    
    getParams 함수는 검색 문자열에서 검색 파라미터를 검색하는 과정을 간소화시켰다.그것은 매개 변수 이름의 그룹을 매개 변수로 하고 그것을 교체한다.매개 변수에 대해 검색 문자열에 존재하는지 확인하고 결과 그룹에 추가합니다.요청한 인자가 검색 문자열에 없으면 추가됩니다. nullnull는 누락된 데이터를 나타내는 특수 JavaScript 값입니다.
    생성된 코드는 매우 짧아서 다른 데이터 집합에 대한 검색을 실현하고 호출자가 실행할 때 제공하는 조건을 바탕으로 쉽게 다시 사용할 수 있다.
    그것은 또 안전한 구멍이 하나 있다.

    느슨한 비교를 남용하다
    느슨한 비교 연산자는 서로 다른 유형의 값을 비교하는 데 사용되는 surprising rules 중 하나nullundefined가 같고 엄격한 비교 알고리즘은 이 두 값을 서로 다른 것으로 간주한다.
    Filter 함수의 비교를 살펴보겠습니다.
    if (items[i][field] == value) {
    
    만약 우리가 한 조작수가alwaysnull이고 다른 조작수가alwaysundefined라고 강제할 수 있다면 비교 결과는 항상true로 되돌아갈 것이다.Google HTTP 포트는 사용자 그룹의 모든 내용을 되돌려줍니다. 이로써 프로그램의 모든 사용자에 대한 민감한 정보를 공개합니다.
    우리가 어떻게 할 수 있겠어?

    공격 페이로드
    비교의 오른쪽은 getParams 함수가 되돌아오는 값이다.우리는... 검색 문자열에서 그것을 완전히 생략해서 이 값을 null 로 설정할 수 있습니다.
    지금 우리는 왼손을 시종일관 되돌릴 수 있는 방법이 필요하다. undefinedundefined는 아직 쓰지 않은 변수 및 객체 속성에 대한 자바스크립트의 특수 값입니다.필드 변수에서 참조하는 속성이 없으면 비교의 왼쪽 전체가 항상 반환됩니다undefined.
    우리는 항상 물체에 어떤 속성이 존재하는지 알지 못한다.약간의 시도와 오류를 통해 부동산 이름이 될 수 없는 값을 찾기가 어렵지 않을 것이다.
    성공적인 공격은 다음과 같습니다.
    GET /profile?field=doesnotexist HTTP/1.1
    Host: localhost:3000
    Connection: keep-alive
    Accept: */*
    
    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Content-Length: 364
    Connection: keep-alive
    
    [{"email":"[email protected]","password":"coldbrew","address":"1234 Wired Brain Blvd\r\nAwesome City, MM 55555"},{"email":"[email protected]","password":"coldbrew","address":"1235 Wired Brain Blvd\r\nAwesome City, MM 55555"},{"email":"[email protected]","password":"coldbrew","address":"1236 Wired Brain Blvd\r\nAwesome City, MM 55555"}]
    

    복구
    이 구멍의 근본 원인은 복구하기 어렵지 않다.=== 연산자는 undefinednull를 다른 값으로 간주한다.비교는 항상false를 되돌려줍니다. 단점은 예상한 대로 users 수조에서 데이터를 되돌려주지 않습니다.
    이 간단한 변경은 이 구멍을 복구했지만, 우리는 할 수 없다.

    더욱 신뢰할 수 있는 복구 방안
    이 빈틈은 비교적 느슨하고 공격자는value 파라미터를 무시할 수 있기 때문에 이용할 수 있습니다.readProfile 함수는 오류를 반환하지 않고 잘못된 입력 데이터로 실행됩니다.
    더 완전한 복구 프로그램은 === 연산자를 사용하지만, 더욱 엄격한 입력 검증을 추가했다.조회 문자열 매개변수가 다음 값이면 끝점이 HTTP 400 응답 코드로 돌아갑니다.

  • 실종되다.매개 변수를 생략하면 의외의 코드 행위를 초래할 수 있습니다.동적과 약한 유형은 우리가 원하지 않는 일을 하더라도 프로그램 작업에 오류가 없다.

  • 유효하지 않습니다.우리는 이 값들이 예상 범위 내에 있는지 검증해야 한다.우리의 예시에서 우리는 field 매개 변수에 대해 이 동작을 실행해야 한다. 우리는 사용자 그룹의 대상이 어떤 속성을 가지고 있는지 알고 다른 값을 사용할 이유가 없다.
  • 친애하는 독자 여러분, 우리는 이 입력 검증 논리를 추가하는 것을 연습으로 당신들에게 남겨 두겠습니다.즐겁게 놀아라!

    다음은요?
    이 시리즈의 다음 글은 일부 안전하지 않은 함수를 사용하여 공격자가 우리의 프로그램에서 코드를 실행할 수 있도록 하는 방법을 설명할 것이다.

    좋은 웹페이지 즐겨찾기