programing tip

RESTful 애플리케이션에서 CSRF를 방지하는 방법은 무엇입니까?

itbloger 2020. 10. 20. 07:22
반응형

RESTful 애플리케이션에서 CSRF를 방지하는 방법은 무엇입니까?


CSRF (Cross Site Request Forgery)는 일반적으로 다음 방법 중 하나로 방지됩니다.

  • 참조 자 확인-RESTful이지만 신뢰할 수 없음
  • 양식에 토큰을 삽입하고 서버 세션에 토큰을 저장하십시오.
  • 암호화 된 일회용 URI-토큰과 같은 이유로 RESTful이 아닙니다.
  • 이 요청에 대해 수동으로 비밀번호 보내기 (HTTP 인증에 사용 된 캐시 된 비밀번호가 아님)-RESTful하지만 편리하지 않음

내 생각은 사용자 비밀, 비밀 스럽지만 정적 인 양식 ID 및 JavaScript를 사용하여 토큰을 생성하는 것입니다.

<form method="POST" action="/someresource" id="7099879082361234103">
    <input type="hidden" name="token" value="generateToken(...)">
    ...
</form>
  1. GET /usersecret/john_doe 인증 된 사용자로부터 JavaScript로 가져옵니다.
  2. 응답 : OK 89070135420357234586534346이 비밀은 개념적으로는 정적이지만 보안을 향상시키기 위해 매일 / 시간마다 변경할 수 있습니다. 이것은 유일한 기밀입니다.
  3. JavaScript로 암호화 된 (그러나 모든 사용자에게는 정적입니다!) 양식 ID를 읽고 사용자 시크릿과 함께 처리하십시오. generateToken(7099879082361234103, 89070135420357234586534346)
  4. 생성 된 토큰과 함께 양식을 서버로 보냅니다.
  5. 서버는 사용자 시크릿과 폼 ID를 알고 있기 때문에 클라이언트가 두 결과를 전송하고 비교하기 전에했던 것과 동일한 generateToken 함수를 실행할 수 있습니다. 두 값이 동일한 경우에만 작업이 승인됩니다.

JavaScript 없이는 작동하지 않는다는 사실에도 불구하고이 접근 방식에 문제가 있습니까?

추가:


여기에는 많은 답변이 있으며 그중 상당수에 문제가 있습니다.

하지 말아야 할 것 :

  1. JavaScript에서 세션 토큰을 읽어야한다면 끔찍하게 잘못한 것입니다. 세션 식별자 쿠키에는 항상 HTTPOnly가 설정되어 있어야 스크립트에서 사용할 수 없습니다.

    이 하나의 보호를 통해 XSS의 영향을 크게 줄일 수 있습니다. 공격자가 더 이상 로그인 한 사용자 세션 토큰을 얻을 수 없기 때문에 모든 의도와 목적을 위해 애플리케이션의 자격 증명과 동일합니다. 왕국에 열쇠를주는 데 하나의 실수를 원하지는 않습니다.

  2. 세션 식별자는 페이지의 내용에 기록되지 않아야합니다. 이는 HTTPOnly를 설정 한 것과 같은 이유 때문입니다. 이는 csrf 토큰이 세션 ID가 될 수 없음을 의미합니다. 다른 값이어야합니다.

해야 할 일 :

  1. OWASP의 지침을 따르십시오 .

  2. 특히 이것이 REST 애플리케이션 인 경우 CSRF 토큰의 이중 제출을 요구할 수 있습니다 . 이렇게하는 경우 상위 도메인 (example.com)이 아닌 특정 전체 도메인 (www.mydomain.com)으로 정의하고 "samesite"쿠키 속성도 활용해야합니다. 인기.

암호화 된 임의의 항목을 생성하고 ASCII Hex 또는 Base64 인코딩으로 저장 한 다음 서버가 페이지를 반환 할 때 쿠키 및 양식에 추가하기 만하면됩니다. 서버 측에서 쿠키 값이 양식 값과 일치하는지 확인하십시오. Voila, CSRF를 죽이고 사용자에게 추가 메시지를 표시하지 않았으며 더 많은 취약점에 노출되지 않았습니다.

참고 : @krubo가 아래에 언급했듯이 이중 제출 기술 에는 몇 가지 약점이있는 것으로 밝혀졌습니다 (이중 제출 참조) . 이 약점에는 다음이 필요하기 때문에 :

  1. 상위 도메인으로 범위가 지정된 쿠키를 정의합니다.
  2. HSTS 설정에 실패했습니다 .
  3. 공격자는 사용자와 서버 사이의 일부 네트워크 위치를 제어합니다.

약점은 "실제 보안 위험"보다는 "멋진 데프콘 토크"범주에 더 많이 해당한다고 생각합니다. 어쨌든 이중 제출을 사용하려는 경우 자신을 완전히 보호하기 위해 몇 가지 추가 조치를 취하는 것이 나쁘지 않습니다.


이게 맞습니까?

  • 쿠키를 통해 로그인 한 사용자를 CSRF로부터 보호하기를 원합니다.
  • 동시에 앱의 Basic, OAuth 및 Digest 인증 요청을위한 RESTful 인터페이스가 필요합니다.

그렇다면 사용자가 쿠키를 통해 로그인했는지 확인 하고 CSRF를 적용한 후에 만 ​​적용하는 것은 어떻습니까?

확실하지 않지만 다른 사이트에서 기본 인증 또는 헤더와 같은 것을 위조 할 수 있습니까?

내가 아는 한 CSRF는 쿠키에 관한 것 입니까? RESTful 인증은 쿠키에서 발생하지 않습니다.


인증 / 승인하려면 서버에 대한 상태가 필요합니다. http 세션 일 필요는 없지만 분산 캐시 (예 : memcached) 또는 데이터베이스에 저장할 수 있습니다.

인증에 쿠키를 사용하는 경우 가장 쉬운 해결 방법은 쿠키 값을 두 번 제출하는 것입니다. 양식을 제출하기 전에 쿠키에서 세션 ID를 읽고 숨겨진 필드에 저장 한 다음 제출하십시오. 서버 측에서 요청의 값이 쿠키에서 가져온 세션 ID와 동일한 지 확인합니다. 다른 도메인의 악한 스크립트는 쿠키에서 세션 ID를 읽을 수 없으므로 CSRF를 방지합니다.

이 체계는 세션 전체에서 단일 식별자를 사용합니다.

더 많은 보호를 원하면 세션별로 고유 ID를 생성하십시오.

또한 JS에서 토큰을 생성하지 마십시오. 누구나 코드를 복사하고 다른 도메인에서 실행하여 사이트를 공격 할 수 있습니다.


정적 양식 ID는 전혀 보호를 제공하지 않습니다. 공격자가 직접 가져올 수 있습니다. 공격자는 클라이언트에서 JavaScript를 사용하도록 제한되지 않습니다. 그는 서버 측에서 정적 양식 ID를 가져올 수 있습니다.

제안 된 변호를 완전히 이해하고 있는지 모르겠습니다. 어디에서 GET /usersecret/john_doe왔습니까? 페이지 JavaScript의 일부입니까? 그것은 문자 그대로 제안 된 URL입니까? 그렇다면 이것이 username비밀이 아니라고 가정합니다. 즉, 브라우저 또는 플러그인 버그가 도메인 간 GET 요청을 허용하는 경우 evil.ru가 사용자 비밀을 복구 할 수 있음을 의미합니다. 도메인 간 GET을 수행 할 수있는 사람이이를 검색 할 수 있도록 허용하는 대신 인증시 사용자 비밀을 쿠키에 저장하지 않는 이유는 무엇입니까?

I would read "Robust Defenses for Cross-Site Forgery" really carefully before I implemented my own authentication system that I wanted to be resistant to CSRF. In fact, I would reconsider implementing my own authentication system at all.


There are a few methods in the CSRF Prevention Cheat Sheet that can be used by restful service. The most RESTful stateless CSRF mitigation is using the Origin or HTTP referer to make sure the requests originate from a domain you trust.


Is something wrong with this approach, despite the fact that it doesn't work without JavaScript?

Your user secret is not a secret if you send it to the client. We usually use such secrets to generate hashes and send them with the form, and wait them back for comparison.

If you want to be RESTful, the request has to contain every information about how to process it. The ways you can do this:

  • Add a csrf token cookie with your REST client and send the same token in hidden input with your forms. If the service and the client are under different domains, you have to share the credentials. On the service you have to compare the 2 tokens, and if they are the same, the request is valid...

  • You can add the csrf token cookie with your REST service and send the same token with the representations of your resources (hidden inputs, etc...). Everything else is the same as the end of the previous solution. This solution is on the edge of RESTfulness. (It is okay until the client do not call the service to modify the cookie. If the cookie is http only, the client should not know about it, if it is not, then the client should set it.) You can do a more complex solution if you add different tokens to each forms and add expiration time to the cookies. You can send the expiration time back with the forms as well, so you will know the reason when a token validation fails.

  • You can have a user secret (different by each user) in the resource state on you service. By building representations, you can generate a token (and expiration time) for each form. You can generate a hash from the actual token (and expiration time, method, url, etc...) and the user secret, and send that hash with the form as well. You keep the "user secret" in secret of course, so you never send that with the form. After that if your service gets a request, you can generate the hash from the request parameters and user secret again, and compare them. If the don't match, the request is invalid...

None of them will protect you if your REST client is javascript injectable, so you have to check all your user content against HTML entities, and remove all of them, or use TextNodes always instead of innerHTML. You have to protect yourself against SQL injection and HTTP header injection as well. Never use simple FTP to refresh your site. And so on... There are many ways to inject evil code into your site...

I almost forgot to mention, that GET requests are always for reading by the service and by the client either. By the service this is obvious, by the client setting any url in the browser must result a representation of a resource or multiple resources, it should never call a POST/PUT/DELETE method on a resource. For example GET http://my.client.com/resource/delete -> DELETE http://my.api.com/resource is a very-very bad solution. But this is very basic skill if you want to hinder CSRF.

참고URL : https://stackoverflow.com/questions/2392100/how-to-prevent-csrf-in-a-restful-application

반응형