JavaScript의 보안 코딩
JavaScript is the front-end of the entire internet. Whether you transpile TypeScript down into JavaScript, create fast little node.js scripts, or build a beautiful-but-dumb front end that calls a much more interesting collection of APIs, it’s literally everywhere. Because JavaScript is so prolific, it’s a prime target for attackers. In this article we will cover ten tips for writing more secure JavaScript.
The number one item to discuss when it comes to JavaScript security is always cross-site scripting (XSS). Cross-site scripting is a form of injection; it means an attacker has confused your application into either interpreting or executing their malicious code instead of treating it as data. User input should always be treated as data, but unfortunately computers can be fooled if we are not careful.
XSS is the one type of injection that works only in JavaScript. It is also the only type of injection that attacks the user directly, by taking control of the browser and using it against the victim. All other types of injections do not attack the user; for instance, SQL injection attacks the database server, command injection attacks the host operating system that the system is running on, and LDAP injection attacks the LDAP server. You get the picture.
With XSS, an attacker can use the browser to access your cookies (including your session information, if you have stored it inside your cookie in an insecure way), external scripts (if you haven’t locked that down using Content Security Policy), install a keylogger, vandalize your website, etc. Anything that JavaScript is cable of doing, an XSS attack can also do; the only limits are an attacker’s imagination.
Although instances of XSS have declined over the years, thanks to various forms of awareness and education (such as The OWASP Top Ten Risks to Web Apps), 출력 인코딩을 자동으로 수행하는 최신 JavaScript 프레임워크, 보안을 이전보다 더 심각하게 고려하는 팀 등 불행하게도 여전히 위험도가 높은 문제입니다.
XSS가 애플리케이션에 영향을 미칠 가능성을 없애려면 다음 작업을 수행하십시오.
- 사용자가 제공했거나 사용자가 수정할 수 있는 모든 데이터에 대해 입력 유효성 검사를 수행합니다. 입력 유효성 검사를 수행한 후 잠재적으로 위험한 문자(예: , ‘, “, – 등)를 허용해야 하는 경우 해당 문자를 이스케이프 처리(앞에 백슬래시 추가)하거나 삭제(문자 그대로 다른 문자로 바꾸거나 완전히 제거)하여 애플리케이션을 보호해야 합니다.
- 표시될 수 있는 모든 항목을 포함하여 화면에 표시될 모든 항목에 대해 출력 인코딩을 수행합니다(예를 들어 프런트 엔드에 표시될 것으로 알고 있는 API에서 무언가를 반환하는 경우). 프레임워크가 이 작업을 수행하도록 할 수 있다면 이것이 이 작업을 올바르게 수행할 수 있는 가장 쉽고 효과적인 방법입니다. 특히 인라인 JavaScript를 수행하는 경우 출력 인코딩이 상당히 복잡해질 수 있습니다. 아무도 중첩 인코딩을 원하지 않습니다!
- 콘텐츠 보안 정책 헤더(CSP)를 사용하여 앱의 일부로 허용할 모든 타사 구성 요소, 특히 스크립트를 나열하세요. 악의적인 XSS 공격이 수행하는 첫 번째 일은 인터넷에 있는 훨씬 더 큰 또 다른 악성 스크립트를 호출하는 것입니다. 대부분의 필드에는 50자 또는 100자만 허용되는데, 이는 공격 코드를 작성하기에 많은 공간이 아닙니다. 그들이 인터넷상의 악의적인 사이트를 호출할 수 있다면 훨씬 더 긴 스크립트를 호출할 수 있으며 위험이 기하급수적으로 증가합니다.
- 추가
httpsOnly
귀하가 뭔가를 놓친 경우 공격자가 귀하의 쿠키에서 귀하의 세션 정보에 절대 접근할 수 없도록 쿠키에 플래그를 지정하세요. 쿠키에 대한 액세스 시도는 XSS 공격이 시도하는 두 번째 작업인 경우가 많으므로 해당 민감한 정보에 액세스하도록 허용하지 마십시오. - 수동 코드 검토를 수행하고, 정적(SAST) 또는 동적(DAST) 분석 도구를 사용하거나, 침투 테스트를 수행하여 누락된 항목이 없는지 절대적으로 확인하세요!
반응, 각도 및[–>Vue.js 자동으로 출력 인코딩을 수행하며 그 밖에도 수많은 놀라운 기능이 있습니다. 어떤 프레임워크를 사용하든 React의 함수처럼 피하거나 주의해야 하는 위험한 기능이 있는지 주의 깊게 확인하세요. dangerouslySetInnerHTML
그리고 Angular의 bypassSecurityTrustAs*
기능.
“단순히 빠른 작업을 수행하려는 경우” HTML에 JavaScript를 직접 포함시키고 싶은 유혹이 있을 수 있지만, 이렇게 하면 XSS의 가능성이 크게 높아집니다(나중에 유지 관리 문제가 발생함). 게다가 엉망이에요. 추가 보안 계층을 유지하려면 JavaScript를 별도의 외부 파일에 보관하세요. 그리고 조직. 모든 것을 깔끔하고 질서 있게 유지하기 위해 CSP 헤더에 스크립트를 정의할 수 있습니다. 이는 인라인 SQL과 유사합니다. 사용자 입력을 결합한 다음 데이터베이스에 직접 입력하여 실행하면 위험한 상황이 발생합니다.
우리는 네안데르탈인이 아닙니다. 이는 물론 우리가 훌륭하고 깨끗하며 구문적으로 올바른 코드를 작성하고 싶다는 것을 의미합니다. 엄격 모드는 다음과 같이 이를 수행하는 데 도움이 됩니다. 조임 더 안전하고 깔끔하며 예측 가능한 코드를 작성하는 데 도움이 되는 언어 규칙입니다. JavaScript뿐만 아니라 제공되는 모든 언어에서 엄격 모드를 사용해야 합니다.
엄격 모드는 자동 오류를 방지하고, 안전하지 않은 작업을 허용하지 않으며, 예약어(예: let
) 의도한 것 이외의 경우에는 우발적인 전역 변수를 방지하고 다음을 사용합니다. this
더 안전하고 예측 가능합니다. 또한 엄격 모드는 성능을 향상시키고, 버그를 더 일찍 발견하고, 모범 사례를 따르도록 돕고, 보안을 향상시킵니다.
이러한 위험 중 다수는 잘 알려져 있으며 오픈 소스 커뮤니티의 개발자는 이를 완화하는 도구를 만들었습니다. 다음과 같은 보다 안전한 코드를 작성하는 데 도움이 되는 유용한 무료 오픈 소스 소프트웨어(FOSS) 라이브러리와 도구를 사용하세요.
- DomPurify XSS에 대한 입력을 삭제합니다.
- Retire.js 오래되었거나 지원되지 않거나 위험한 JavaScript 라이브러리를 찾습니다.
- Npm Audit,[–>Yarn Audit,[–>Snyk CLI (무료 버전) 종속성이 최신인지 확인하세요.
- DOM Snitch는 개발자와 테스터가 클라이언트 측 코드에서 일반적으로 발견되는 안전하지 않은 관행을 식별할 수 있도록 하는 실험적인 Chrome 확장 프로그램을 만든 Google 프로젝트입니다.
- Nodejsscan node.js 앱을 위한 무료 정적 분석 도구입니다.
- Semgrep Community edition,[–>Bearer CLI (무료 버전),[–>Horusec 등을 사용하여 무료 정적 분석을 수행합니다. 그들은 모두 JavaScript를 포함한 여러 언어로 작동합니다.
- Zap 자유 동적 분석(DAST)을 수행합니다. 메모: 달리기 전에 상사의 허락을 받으세요[–>Zap 직장에서! 이는 해커 도구이며 서면 허가 없이 웹사이트나 앱에 대해 실행하는 것은 불법입니다. 이 도구를 잘못 사용하면 손상될 수 있습니다. 사용하시기 전에 꼭 읽어보시기 바랍니다. 다른 도구는 사용하기에 결코 위험하지 않습니다.
텍스트는 텍스트이고 변수 내부에 있는 것은 무엇이든 텍스트라는 점을 코드에서 명확하게 설명하세요. ~ 아니다 실행되거나 해석되어야 하는 코드입니다. 우리는 사용자의 모든 내용을 JavaScript 또는 CSS용 안전한 데이터 요소에 입력하여 텍스트가 텍스트인지 확인합니다. 예를 들어 다음을 사용하지 마십시오. innerHtml
(렌더링됨); 대신 사용 innerText
또는 textContent
명확하게 텍스트로만 제공되며 표시용이며 해석되지 않습니다. 항상 텍스트라는 점을 분명히 하세요. DOM(문서 개체 모델)이 결정하도록 두지 마십시오. 때로는 DOM이 잘못될 수도 있기 때문입니다.
꼭 설정해야 한다면 element.setAttribute
변수의 데이터(종종 사용자가 제공한 값이므로 잠재적으로 위험함)의 경우 동적(변경 가능) 속성보다는 안전하고 정적 속성만 사용하십시오. 안전한 속성의 예는 다음과 같습니다. align
, alink
, alt
, bgcolor
, border
, cellpadding
, cellspacing
, class
, color
, cols
, colspan
, coords
, dir
, face
, height
, hspace
, ismap
, lang
, marginheight
, marginwidth
, multiple
, nohref
, noresize
, noshade
, nowrap
, ref
, rel
, rev
, rows
, rowspan
, scrolling
, shape
, span
, summary
, tabindex
, title
, usemap
, valign
, value
, vlink
, vspace
, width
). 하지 마십시오 다음에 대해 동적이며 안전하지 않은 속성을 사용합니다. element.setAttribute
~와 같은 onclick
또는 onblur
. 어떤 일이 발생하거나 변경되는 속성은 안전하지 않으며 사용자 제공 데이터(예: 변수에 저장된 모든 데이터)와 함께 사용하면 안 됩니다.
변수(사용자 데이터) 사용에 관한 주제는…컨텍스트가 아닌 CSS 속성 값 내부에만 배치되어야 합니다. 다시 말하지만, 우리는 그들이 우리 소프트웨어를 예측할 수 없는 방식으로 작동하게 만드는 것을 원하지 않습니다.
예:
When performing input validation for security reasons (not for usability, speed, or any other reason), the checks must be performed on the backend, not in the front end. Anyone with an intercept proxy, such as Zap or Burp Suite, is able to ‘intercept’ your front end’s request, make changes to it, and then pass it onto the backend as though it was not interfered with. If done well, the backend has no idea if someone made any changes to a request after it left the front end. This type of attack or testing would be performed on the same machine as the person using the application, meaning they would not need to worry about encryption, they would have direct access in clear text to your entire request.
Why is this bad? Imagine you have input validation in your JavaScript that says you are willing to accept a-z, upper and lower case, as well as all numbers, but nothing else. It accepts this data and then reflects to back to the screen for the user to read. The app would theoretically reject the following input “‘ or 1=1 --”
왜냐하면 그 캐릭터 중 몇몇은 당신의 캐릭터에 없기 때문입니다. allowlist
. 그러나 공격자가 인터셉트 프록시와 함께 애플리케이션을 사용하고 있다고 상상해 보십시오. 공격자는 필드에 “Hello”를 입력하고 입력 유효성 검사를 통과합니다. 그런 다음 귀하의 요청을 가로채서 다음과 같이 필드를 변경합니다. “ ‘ or 1=1 --”
그런 다음 이를 애플리케이션으로 보냅니다. 백엔드에 입력 유효성 검사가 없는 경우 애플리케이션은 해당 데이터를 일반적으로 사용하는 방식으로 사용합니다. 이 경우 잠재적으로 다음과 같은 SQL 문에 데이터를 추가합니다. ‘select * from table users where username like %’ & your_now_malicious_variable_here & ‘ and password = ‘ & password_variable
.
이는 단순화된 예이지만 보안상의 이유로 입력 유효성 검사는 백엔드에서 수행되어야 한다는 것을 알 수 있기를 바랍니다. 속도와 유용성을 위해 언제든지 프런트 엔드에서도 수행할 수 있습니다. 최종 결정이 항상 서버에 있는지 확인하면 됩니다.
자주 문제가 되는 다음 JavaScript 함수를 사용하지 마세요. 특히 사용자가 제공하거나 사용자가 수정할 수 있는 데이터와 함께 사용하려는 경우 더욱 그렇습니다. 반드시 사용해야 하는 경우 각별히 주의하여 사용하세요. eval()
, innerHTML
, outerHTML
, Function()
, escape()
, unescaped()
, document.write()
, document.writeln()
, unescapeHTML()
, decodeURI()
그리고 encodeURI()
, with()
문자열 인수(변수를 의미)를 사용하는 생성자, setTimeout()
, setInterval()
, new function
그리고 setAttribute()
(기억하세요: 만약 당신이 사용한다면 setAttribute
정적 값만 사용하세요).
입력 유효성 검사/삭제/이스케이프 수행, 인라인/동적 쿼리 작성 대신 매개변수화된 쿼리 사용, 전송 중 및 저장 중인 데이터 암호화, 인증, 권한 부여, 세션 관리, ID 및 비밀 관리 등을 위한 신뢰할 수 있는 시스템 사용 등 다른 애플리케이션에서 수행하는 기타 모든 보안 코딩 전략을 수행합니다.
대부분의 사람들이 ‘시큐어 코딩’의 일부로 간주하는 표준 항목 중에서 팀이 보안 시스템 개발 수명 주기(S-SDLC)를 따르도록 하는 것이 가장 중요합니다. 내가 말할 때 안전한 SDLC는 귀하의 팀이 귀하가 구축하고 유지 관리하는 소프트웨어가 안전하고 안정적이며 견고하다는 것을 보장하기 위해 추가 활동과 프로세스를 추가한다는 것을 의미합니다. 방법론에 추가할 수 있는 활동에는 위협 모델링, 보안 코드 검토, 자동화된 동적 테스트, 소프트웨어 구성 분석 또는 기타 타사 종속성 확인, 소프트웨어 공급망 강화, 보안 사용자 스토리 생성, 기타 모든 프로젝트 요구 사항과 함께 보안 요구 사항 포함 등이 있습니다. SDLC에 추가하는 모든 보안 활동은 사용자가 신뢰할 수 있는 더욱 강력하고 신뢰할 수 있는 시스템을 만드는 데 도움이 됩니다. 더 많이 추가할수록 좋습니다!
보다 안전한 JavaScript를 작성하기 위한 여정은 작고 일관된 변경으로 시작됩니다. 하나 또는 두 개의 모범 사례를 선택하고 지금 바로 실행해 보세요. 그 영향이 보이기 시작하면 잠시 시간을 내어 배운 내용을 친구나 동료와 공유해 보세요. 지식 공유와 점진적인 개선을 통해 우리는 JavaScript를 더욱 아름답고 강력할 뿐만 아니라 모두에게 더욱 안전하게 만들 수 있습니다.
Post Comment