외부 API의 예상치 못한 값으로부터 보호해야합니까?


51

외부 API에서 입력을받는 함수를 코딩한다고 가정 해 봅시다 MyAPI.

해당 외부 API MyAPI에는 a string또는 a를 반환한다는 계약이 있습니다 number.

이 같은 일을 방지하는 것이 좋습니다 null, undefined, boolean그것의 API의 일부가 아닌 비록 등 MyAPI? 특히 API를 제어 할 수 없으므로 정적 유형 분석과 같은 것을 통해 보장 할 수 없으므로 미안한 것보다 안전합니까?

나는 견고성 원칙 과 관련하여 생각하고 있습니다.


16
예상치 못한 값이 반환되면 처리하지 않으면 어떤 영향이 있습니까? 이러한 영향으로 살 수 있습니까? 영향을 처리하지 않도록 예기치 않은 값을 처리하는 것이 복잡 할 가치가 있습니까?
Vincent Savard

55
당신이 그들을 기대한다면, 정의에 따르면 예상치 못한 것이 아닙니다.
메이슨 휠러

28
API는 유효한 JSON을 다시 제공해야 할 의무는 없습니다 (이것이 JSON이라고 가정합니다). 다음과 같은 회신을받을 수도 있습니다<!doctype html><html><head><title>504 Gateway Timeout</title></head><body>The server was unable to process your request. Make sure you have typed the address correctly. If the problem persists, please try again later.</body></html>
user253751

5
"외부 API"란 무엇입니까? 여전히 귀하의 통제하에 있습니까?
중복 제거기

11
"좋은 프로그래머는 일방 통행 길을 건너기 전에 두 가지 방법을 찾는 사람입니다."
jeroen_de_schutter

답변:


103

소스에 관계없이 소프트웨어의 입력을 신뢰해서는 안됩니다. 유형의 유효성을 검사하는 것뿐만 아니라 입력 범위와 비즈니스 논리도 중요합니다. 코멘트 당, 이것은 OWASP에 의해 잘 설명되어 있습니다

그렇게하지 않으면 나중에 정리해야하는 가비지 데이터가 남게되지만 최악의 경우 업스트림 서비스가 어떤 식 으로든 손상된 경우 악의적 인 악용 가능성이 생깁니다 (qv 대상 해킹). 그 사이의 문제 범위에는 응용 프로그램을 복구 할 수없는 상태로 만드는 것이 포함됩니다.


의견에서 나는 아마도 내 대답이 약간의 확장을 사용할 수 있음을 알 수 있습니다.

"입력을 신뢰하지 마십시오"라는 말은 업스트림 또는 다운 스트림 시스템에서 항상 유효하고 신뢰할 수있는 정보를 수신한다고 가정 할 수 없기 때문에 항상 입력을 최대한 활용하거나 거부해야합니다. 그것.

한 가지 주장은 예를 들어 설명 할 주석에 나타납니다. 예, OS를 어느 정도 신뢰해야하지만 예를 들어 1에서 10 사이의 숫자를 요청하고 "bob"으로 응답하는 경우 임의의 숫자 생성기 결과를 거부하는 것은 부당하지 않습니다.

마찬가지로 OP의 경우 응용 프로그램이 업스트림 서비스의 유효한 입력 만 수락하는지 확인해야합니다. 그것이 좋지 않을 때하는 일은 당신에게 달려 있으며, 달성하려는 실제 비즈니스 기능에 크게 달려 있지만 최소한 디버깅을 위해 로그를 기록하고 그렇지 않으면 응용 프로그램이 작동하지 않도록해야합니다 회복 불가능하거나 불안전 한 상태로.

누군가 / 뭔가 당신에게 줄 수있는 모든 가능한 입력을 알 수는 없지만, 비즈니스 요구 사항에 따라 허용되는 것을 제한하고이를 기반으로 입력 허용 목록을 만들 수 있습니다.


20
qv는 무엇을 의미합니까?
JonH

15
@JonH는 기본적으로 "참조"합니다 ... Target hack은 en.oxforddictionaries.com/definition/qv를 참조하는 예입니다 .
andrewtweber

8
이 대답은 의미가 없으므로 이해되지 않습니다. 써드 파티 라이브러리가 오작동 할 수있는 모든 방법을 예상하는 것은 불가능합니다. 라이브러리 함수의 문서에서 결과에 항상 일부 속성이 있음을 명시 적으로 보증하는 경우 설계자가이 속성이 실제로 유지되도록 보장 할 수 있습니다. 그건 그들의 이런 종류의 일을 확인하는 테스트 스위트가 있고, 그렇지 않은 경우 상황이 발생했을 경우에 버그 수정 제출 책임. 당신 자신의 코드에서 이러한 속성을 확인는 DRY 원칙을 위반한다.
왼쪽

23
@leftaroundabout no, 그러나 응용 프로그램이 나머지를 수락하고 거부 할 수있는 모든 유효한 것을 예측할 수 있어야합니다.
바울

10
@leftaroundabout 모든 것을 불신하는 것이 아니라, 신뢰할 수없는 외부의 출처를 불신하는 것에 관한 것입니다. 이것은 위협 모델링에 관한 것입니다. 소프트웨어가 안전하지 않은 것을하지 않은 경우 (어떤 종류의 행위자와 위협에 대해 응용 프로그램을 보호하고 싶지 않은지 어떻게 알 수 있습니까?) 밀 비즈니스 소프트웨어를 실행하는 경우 발신자가 악의적 일 수 있다고 가정하는 것이 합리적이며, OS가 위협이라고 가정하는 것은 거의 없습니다.
Voo

33

, 물론. 그러나 대답이 다를 수 있다고 생각하는 것은 무엇입니까?

API가 계약서의 내용을 API가 반환하지 않는 경우 프로그램이 예기치 않은 방식으로 작동하게하고 싶지는 않습니까? 그래서 적어도 당신은 그런 행동을 어떻게 든 처리해야합니다 . 최소한의 형태의 오류 처리는 항상 (매우 최소한!) 노력할만한 가치가 있으며 이와 같은 것을 구현하지 않은 것에 대한 변명은 절대 없습니다.

그러나 이러한 경우를 처리하기 위해 얼마나 많은 노력을 기울여야하는지에 따라 많은 비용이 소요되며 시스템 상황에서만 답변 할 수 있습니다. 종종 짧은 로그 항목으로 응용 프로그램을 정상적으로 종료하는 것으로 충분할 수 있습니다. 때때로, 다른 형태의 "잘못된"리턴 값을 처리하고 일부 대체 전략을 구현해야하는 자세한 예외 처리를 구현하는 것이 좋습니다.

그러나 사내 스프레드 시트 서식 응용 프로그램을 작성하거나 10 명 미만이 사용하고 응용 프로그램 충돌의 재정적 영향이 매우 낮은 경우 또는 새로운 자율 주행 자동차를 만드는 경우에는 큰 차이가 있습니다. 애플리케이션 크래쉬가 생명을 소비 할 수있는 시스템.

따라서 자신이하고있는 일을 반영하는 것에 대한 지름길은 없습니다 . 상식을 사용하는 것이 항상 필수입니다.


해야 할 일은 또 다른 결정입니다. 장애 조치 솔루션이있을 수 있습니다. 예외 로그 (또는 데드 레터)를 작성하기 전에 비동기 적으로 재 시도 할 수 있습니다. 문제가 지속되면 공급 업체 나 공급 업체에 활성 경고가 옵션이 될 수 있습니다.
mckenzm

@mckenzm : OP가 문자 그대로의 대답이 명백히 "예"일 수있는 곳에 질문을한다는 사실은 문자 그대로의 대답에만 관심이없는 IMHO 부호입니다. 그들은 "API에서 예기치 않은 값의 다른 형태를 보호하고 다르게 처리해야 합니까? " 라고 묻고있는 것 같습니다 .
Doc Brown

1
흠, 쓰레기 / 잉어 / 다이 접근. 잘못된 (그러나 합법적 인) 요청을 전달하는 것이 우리의 잘못입니까? 응답은 가능하지만 특히 사용할 수는 없습니까? 또는 응답이 손상 되었습니까? 다른 시나리오, 이제 숙제처럼 들립니다.
mckenzm

21

견고성 원칙, 특히 "반드시 받아들이는 것에서 자유 롭다"는 소프트웨어에서 매우 나쁜 생각입니다. 물리적 제약으로 인해 엔지니어링 공차가 매우 중요한 하드웨어 환경에서 개발되었지만 소프트웨어에서 누군가가 잘못된 입력이나 부적절한 입력을 보내면 두 가지 선택이 있습니다. 그것을 거부하거나 (바람직하게 무엇이 잘못되었는지에 대한 설명과 함께) 거부하거나 의미하는 바를 알아 내려고 시도 할 수 있습니다.

편집 : 위의 진술에서 내가 틀렸다는 것이 밝혀졌습니다. 견고성 원칙은 하드웨어의 세계가 아니라 인터넷 아키텍처, 특히 RFC 1958 에서 나옵니다 . 상태는 다음과 같습니다.

3.9 보낼 때 엄격하고주의를 기울여야한다. 구현은 네트워크로 전송할 때 사양을 정확하게 따르고 네트워크에서 잘못된 입력을 허용해야합니다. 확실하지 않은 경우 사양에서 요구하지 않는 한 오류 메시지를 반환하지 않고 결함이있는 입력을 자동으로 폐기하십시오.

이것은 분명히 말해서 처음부터 끝까지 잘못되었습니다. 이 포스트에서 제시된 이유로 "오류 메시지를 리턴하지 않고 자동으로 결함 입력을 폐기"하는 것보다 잘못된 오류 처리 개념을 생각하기가 어렵습니다.

이 점에 대한 자세한 내용은 IETF 논문 견고성 원칙의 유해한 결과를 참조하십시오 .

결코, 결코, 결코 당신이 당신의 프로젝트에 던질 구글의 검색 팀에 해당 자원이 없다면 그게 특정 문제 영역에서 좋은 직업에 가까운 무엇을하는 컴퓨터 프로그램을 마련하는 데 걸리는 무엇 때문에, 그 두 번째 옵션을 선택합니다. (그런데도 Google의 제안은 반 시간 동안 왼쪽에서 곧바로 나오는 것처럼 느껴집니다.) 그렇게하면 결국 프로그램이 자주 해석하려고하는 엄청난 두통이 생깁니다. 발신자가 실제로 의미했던 것이 Y 일 때 X로 잘못된 입력.

이것은 두 가지 이유로 나쁩니다. 분명한 것은 시스템에 잘못된 데이터가 있기 때문입니다. 덜 명백한 것은 많은 경우에, 당신이나 보낸 사람 모두가 당신의 얼굴에 무언가가 터질 때 길을 훨씬 늦게까지 잘못되었다는 것을 깨닫지 못할 것입니다. 눈에 띄는 효과가 근본 원인에서 지금까지 제거 되었기 때문에 잘못되었습니다.

이것이 바로 Fail Fast 원칙이 존재하는 이유입니다. 두통을 API에 적용하여 두통과 관련된 모든 사람을 구하십시오.


7
나는 당신이 말하는 것의 원칙에 동의하지만, 당신은 WRT를 견고성 원칙의 의도로 착각했다고 생각합니다. 나는 그것이 "잘못된 데이터를 받아 들인다"는 것을 의미하는 것을 본 적이 없다. 예를 들어, 입력이 CSV 파일 인 경우 Robustness Principle은 날짜를 예기치 않은 형식으로 구문 분석하는 데 유효한 인수는 아니지만 헤더 행에서 열 순서를 유추하는 것이 좋습니다. .
Morgen

9
@Morgen : 견고성 원칙은 브라우저가 느슨한 HTML을 수용해야한다고 제안하는 데 사용되었으며, 배포 된 웹 사이트는 브라우저가 적절한 HTML을 요구했을 때보 다 훨씬 더 가파르게되었습니다. 그러나 거기에서 문제의 큰 부분은 사람이 생성하고 기계로 생성하는 컨텐츠에 공통 형식을 사용하는 것과는 달리 별도의 사람이 편집 할 수 있고 기계가 분석 할 수있는 형식을 유틸리티와 함께 ​​사용하여 변환하는 것입니다.
supercat

9
@supercat : 그럼에도 불구하고-또는 그냥-HTML과 WWW는 매우 성공적이었다 ;-)
Doc Brown

11
@DocBrown : 정말 많은 끔찍한 것들이 표준이되었습니다. 왜냐하면 그들은 많은 영향력을 가진 누군가가 최소한의 특정 기준을 충족시키는 것을 채택해야 할 때 이용 가능한 최초의 접근 방식 이었기 때문입니다. 더 나은 것을 선택하기에는 너무 늦었습니다.
supercat

5
@supercat 정확합니다. 예를 들어 JavaScript는 즉시 떠 오릅니다.
Mason Wheeler

13

일반적으로 코드는 실용 할 때마다 다음과 같은 제약 조건을 유지하도록 구성되어야합니다.

  1. 올바른 입력이 주어지면 올바른 출력을 생성하십시오.

  2. 올바른 입력이 제공되면 (올바르거나 올바르지 않을 수 있음) 유효한 출력을 생성하십시오 (같은).

  3. 유효하지 않은 입력이 주어지면, 정상 입력으로 인한 것 이상이나 오류 신호로 정의 된 것 이상의 부작용없이 처리하십시오.

많은 상황에서 프로그램은 본질적으로 그들이 유효한 지에 대해 신경 쓰지 않고 다양한 데이터 청크를 통과합니다. 이러한 청크에 유효하지 않은 데이터가 포함되어 있으면 프로그램의 결과에 유효하지 않은 데이터가 포함될 수 있습니다. 프로그램이 모든 데이터의 유효성을 검사하도록 특별히 설계되지 않은 한 , 유효하지 않은 입력이 주어 졌을 때도 유효하지 않은 출력을 생성하지 않도록 보장하는 경우 , 출력을 처리하는 프로그램은 그 안에 유효하지 않은 데이터가있을 가능성을 허용해야합니다.

데이터를 조기에 검증하는 것이 종종 바람직하지만 항상 실용적이지는 않습니다. 무엇보다도, 하나의 데이터 청크의 유효성이 다른 청크의 내용에 의존하고 일부 단계 시퀀스로 공급되는 대부분의 데이터가 도중에 필터링되어 유효성을 데이터로 제한하는 경우 모든 단계는 모든 것을 검증하는 것보다 훨씬 나은 성능을 제공 할 수 있습니다.

또한, 프로그램 만 사전 검증 된 데이터를 제공 할 것으로 예상된다하더라도 그것이 위의 제약 조건을 유지해야하는 것이 좋은 어쨌든 때마다 실제. 모든 처리 단계에서 전체 유효성 검사를 반복하면 성능이 크게 저하 될 수 있지만 위의 제약 조건을 유지하는 데 필요한 제한된 양의 유효성 검사가 훨씬 저렴할 수 있습니다.


그런 다음 API 호출 결과가 "입력"인지 여부를 결정합니다.
mastov

@mastov : 많은 질문에 대한 답은 "입력"과 "관찰 가능한 행동"/ "출력"을 어떻게 정의하는지에 달려 있습니다. 프로그램의 목적이 파일에 저장된 숫자를 처리하는 것이라면, 그 입력은 숫자의 시퀀스 (이 경우 숫자가 아닌 것은 입력이 불가능한) 또는 파일 (이 경우에는 파일에 나타날 수 있습니다 (입력 가능).
supercat

3

두 시나리오를 비교하고 결론을 도출해 봅시다.

시나리오 1 우리의 응용 프로그램은 계약에 따라 외부 API가 작동한다고 가정합니다.

시나리오 2 우리의 응용 프로그램은 외부 API가 오작동 할 수 있다고 가정하므로 예방 조치를 추가하십시오.

일반적으로 API 또는 소프트웨어가 계약을 위반할 가능성이 있습니다. 버그 또는 예기치 않은 조건으로 인한 것일 수 있습니다. API조차도 내부 시스템에 문제가있어 예기치 않은 결과가 발생할 수 있습니다.

외부 API가 계약을 준수하고 예방 조치를 추가하지 않는다고 가정하여 프로그램이 작성된 경우; 누가이 문제에 직면하게 될까요? 통합 코드를 작성한 사람은 우리 일 것입니다.

예를 들어, 선택한 널값입니다. API 계약에 따라 응답에 null 값이 없어야합니다. 그러나 프로그램이 갑자기 위반되면 NPE가 발생합니다.

따라서 응용 프로그램에 예기치 않은 시나리오를 해결하기위한 추가 코드가 있는지 확인하는 것이 좋습니다.


1

수신 데이터 (사용자가 입력했거나 그렇지 않은 경우)를 항상 검증해야하므로이 외부 API에서 검색된 데이터가 유효하지 않은 경우 처리 할 프로세스가 있어야합니다.

일반적으로 조직 외부 시스템이 만나는 이음새에는 인증, 인증 (간단히 인증으로 정의되지 않은 경우) 및 유효성 검사가 필요합니다.


1

일반적으로 그렇습니다. 결함이있는 입력에 대해 항상 보호해야하지만 API의 종류에 따라 "guard"는 다른 것을 의미합니다.

서버에 대한 외부 API의 경우 실수로 서버 상태를 손상 시키거나 손상시키는 명령을 작성하지 않으려는 경우이를 방지해야합니다.

예를 들어 컨테이너 클래스 (목록, 벡터 등)와 같은 API의 경우 예외를 던지는 것은 완벽하게 훌륭한 결과입니다. 클래스 인스턴스의 상태를 손상시키는 것은 어느 정도 수용 가능할 수 있습니다 (예 : 잘못된 비교 연산자가 제공된 정렬 된 컨테이너는 응용 프로그램 충돌이 허용 될 수도 있지만 응용 프로그램의 상태를 손상시키는 것 (예 : 클래스 인스턴스와 관련이없는 임의의 메모리 위치에 쓰는 것)은 아닐 수 있습니다.


0

약간 다른 의견을 제시하기 위해 : 계약을 위반하더라도 주어진 데이터로 작업하는 것이 용납 될 수 있다고 생각합니다. 사용법에 따라 다릅니다. 문자열이어야합니다. 또는 표시 중이거나 사용하지 않는 것입니다. 후자의 경우 간단히 받아들입니다. 다른 API에서 제공하는 데이터의 1 % 만 필요한 API가 있습니다. 나는 99 %의 데이터가 어떤 종류인지 신경 쓰지 않았으므로 결코 확인하지 않을 것입니다.

"입력을 충분히 확인하지 않아 오류 발생"과 "너무 엄격해서 유효한 데이터를 거부합니다"사이에는 균형이 있어야합니다.


2
"다른 API가 제공하는 데이터의 1 % 만 필요한 API가 있습니다." 그러면 API가 실제로 필요한 것보다 100 배 더 많은 데이터를 기대하는 이유를 알 수 있습니다. 전달하기 위해 불투명 한 데이터를 저장해야하는 경우 데이터가 무엇인지 구체적으로 지정할 필요가 없으며 특정 형식으로 선언 할 필요가 없습니다.이 경우 발신자가 계약을 위반하지 않습니다 .
Voo

1
@Voo-내 의심은 외부 API (예 : "도시 X의 날씨 세부 정보 가져 오기")를 호출 한 다음 필요한 데이터 ( "현재 온도")를 선택하고 나머지 반환 된 데이터 ( "강우"를 무시 함) ","바람 ","예보 온도 ","바람 냉각 "등 ...)
Stobor

@ChristianSauer-나는 당신이 더 넓은 합의와는 거리가 멀다고 생각합니다-사용하는 데이터의 1 %는 확인하는 것이 합리적이지만 99 %는 반드시 확인 할 필요는 없습니다. 코드가 넘어 질 수있는 것들만 확인하면됩니다.
Stobor

0

나는 항상 내 시스템에 대한 모든 입력을 항상 점검해야한다. 즉, 프로그램에서 사용하지 않더라도 API에서 반환 된 모든 매개 변수를 확인해야합니다. API에 보내는 모든 매개 변수가 올바른지 확인하는 경향이 있습니다. 이 규칙에는 두 가지 예외 만 있습니다 (아래 참조).

테스트 이유는 어떤 이유로 든 API / 입력이 올바르지 않으면 내 프로그램이 아무것도 의존 할 수 없기 때문입니다. 어쩌면 내 프로그램이 내가 믿는 것과 다른 것을 수행하는 이전 버전의 API에 연결되었을 수 있습니까? 어쩌면 내 프로그램은 이전에 결코 없었던 외부 프로그램의 버그로 넘어졌습니다. 또는 더 나쁜 것은 항상 발생하지만 아무도 신경 쓰지 않습니다! 어쩌면 외부 프로그램이 해커에 의해 속여 내 프로그램이나 시스템을 손상시킬 수있는 물건을 반환하고 있습니까?

내 세상의 모든 것을 테스트하는 두 가지 예외는 다음과 같습니다.

  1. 신중하게 성능을 측정 한 후의 성능 :

    • 측정하기 전에 최적화하지 마십시오. 모든 입력 / 반환 된 데이터를 테스트하는 것은 실제 호출에 비해 매우 작은 시간이 걸리므로 제거하면 거의 또는 전혀 절약됩니다. 여전히 오류 감지 코드를 유지하지만 매크로 또는 주석 처리하여 주석 처리합니다.
  2. 오류와 관련하여 실마리가 없을 때

    • 디자인에서 단순히 발견 된 오류를 처리 할 수없는 경우가 종종 있습니다. 어쩌면 당신이해야 할 일은 오류를 기록하는 것이지만 시스템에는 오류 기록이 없습니다. 최소한 개발자로서 나중에 확인할 수 있도록 오류를 "기억"하는 방법을 찾는 것이 거의 항상 가능합니다. 로깅을하지 않더라도 오류 카운터는 시스템에 보유하는 좋은 방법입니다.

정확히 입력 / 반환 값을 확인하는 것이 중요한 질문입니다. 예를 들어 API가 문자열을 반환한다고 말하면 다음을 확인합니다.

  • 데이터 유형은 문자열입니다.

  • 그 길이는 최소값과 최대 값 사이입니다. 프로그램에서 처리 할 수있는 최대 크기의 문자열을 항상 확인하십시오 (너무 큰 문자열을 반환하는 것은 네트워크 시스템에서 일반적인 보안 문제입니다).

  • 일부 문자열은 "불법적 인"문자 또는 내용과 관련이 있는지 확인해야합니다. 프로그램이 나중에 데이터베이스를 말하기 위해 문자열을 보낼 수있는 경우 데이터베이스 공격을 확인하는 것이 좋습니다 (SQL 삽입 검색). 이 테스트는 시스템의 경계에서 가장 잘 수행되며, 여기서 공격의 출처를 파악하고 조기에 실패 할 수 있습니다. 문자열을 나중에 결합 할 때 전체 SQL 인젝션 테스트를 수행하는 것이 어려울 수 있으므로 데이터베이스를 호출하기 전에 테스트를 수행해야하지만 일부 문제를 일찍 발견하면 유용 할 수 있습니다.

API로 전송하는 매개 변수를 테스트하는 이유는 올바른 결과를 다시 얻도록하기위한 것입니다. 다시 말하지만 API를 호출하기 전에 이러한 테스트를 수행하는 것은 불필요 해 보일 수 있지만 성능이 거의 떨어지고 프로그램에서 오류가 발생할 수 있습니다. 따라서 테스트는 시스템을 개발할 때 가장 중요합니다 (현재는 모든 시스템이 지속적으로 개발중인 것 같습니다). 매개 변수에 따라 테스트가 다소 철저 할 수는 있지만 프로그램에서 만들 수있는 대부분의 매개 변수에 허용되는 최소 및 최대 값을 설정할 수있는 경향이 있습니다. 아마도 문자열은 항상 2 자 이상이어야하고 최대 2000 자 여야합니까? 내 프로그램이 일부 매개 변수의 전체 범위를 절대 사용하지 않는다는 것을 알기 때문에 최소 및 최대는 API가 허용하는 범위 안에 있어야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.