48 KiB
Angular
The Checklist
Checklist from here.
- Angular को एक क्लाइंट-साइड फ्रेमवर्क माना जाता है और इसे सर्वर-साइड सुरक्षा प्रदान करने की अपेक्षा नहीं की जाती है
- प्रोजेक्ट कॉन्फ़िगरेशन में स्क्रिप्ट के लिए सोर्समैप अक्षम है
- अविश्वसनीय उपयोगकर्ता इनपुट को हमेशा टेम्पलेट्स में उपयोग करने से पहले इंटरपोलेट या सैनीटाइज किया जाता है
- उपयोगकर्ता के पास सर्वर-साइड या क्लाइंट-साइड टेम्पलेट्स पर कोई नियंत्रण नहीं है
- अविश्वसनीय उपयोगकर्ता इनपुट को एप्लिकेशन द्वारा विश्वसनीय होने से पहले एक उपयुक्त सुरक्षा संदर्भ का उपयोग करके सैनीटाइज किया जाता है
BypassSecurity*
विधियों का अविश्वसनीय इनपुट के साथ उपयोग नहीं किया जाता है- अविश्वसनीय उपयोगकर्ता इनपुट को Angular क्लासेस जैसे
ElementRef
,Renderer2
औरDocument
, या अन्य JQuery/DOM सिंक्स में नहीं भेजा जाता है
What is Angular
Angular एक शक्तिशाली और ओपन-सोर्स फ्रंट-एंड फ्रेमवर्क है जिसे Google द्वारा बनाए रखा जाता है। यह कोड की पठनीयता और डिबगिंग को बढ़ाने के लिए TypeScript का उपयोग करता है। मजबूत सुरक्षा तंत्र के साथ, Angular सामान्य क्लाइंट-साइड कमजोरियों जैसे XSS और open redirects को रोकता है। इसे सर्वर-साइड पर भी उपयोग किया जा सकता है, जिससे दोनों कोणों से सुरक्षा पर विचार करना महत्वपूर्ण हो जाता है।
Framework architecture
Angular के मूलभूत सिद्धांतों को बेहतर ढंग से समझने के लिए, आइए इसके आवश्यक अवधारणाओं के माध्यम से चलते हैं।
सामान्य Angular प्रोजेक्ट आमतौर पर इस तरह दिखता है:
my-workspace/
├── ... #workspace-wide configuration files
├── src
│ ├── app
│ │ ├── app.module.ts #defines the root module, that tells Angular how to assemble the application
│ │ ├── app.component.ts #defines the logic for the application's root component
│ │ ├── app.component.html #defines the HTML template associated with the root component
│ │ ├── app.component.css #defines the base CSS stylesheet for the root component
│ │ ├── app.component.spec.ts #defines a unit test for the root component
│ │ └── app-routing.module.ts #provides routing capability for the application
│ ├── lib
│ │ └── src #library-specific configuration files
│ ├── index.html #main HTML page, where the component will be rendered in
│ └── ... #application-specific configuration files
├── angular.json #provides workspace-wide and project-specific configuration defaults
└── tsconfig.json #provides the base TypeScript configuration for projects in the workspace
अन्य दस्तावेज़ के अनुसार, हर Angular एप्लिकेशन में कम से कम एक घटक होता है, रूट घटक (AppComponent
) जो घटक पदानुक्रम को DOM से जोड़ता है। प्रत्येक घटक एक वर्ग को परिभाषित करता है जिसमें एप्लिकेशन डेटा और लॉजिक होता है, और यह एक HTML टेम्पलेट से संबंधित होता है जो एक लक्षित वातावरण में प्रदर्शित होने वाले दृश्य को परिभाषित करता है। @Component()
डेकोरेटर उस वर्ग को घटक के रूप में पहचानता है जो इसके ठीक नीचे है, और टेम्पलेट और संबंधित घटक-विशिष्ट मेटाडेटा प्रदान करता है। AppComponent
को app.component.ts
फ़ाइल में परिभाषित किया गया है।
Angular NgModules एक एप्लिकेशन डोमेन, एक कार्यप्रवाह, या निकटता से संबंधित क्षमताओं के सेट के लिए एक संकलन संदर्भ घोषित करते हैं। हर Angular एप्लिकेशन में एक रूट मॉड्यूल होता है, जिसे पारंपरिक रूप से AppModule
कहा जाता है, जो एप्लिकेशन को लॉन्च करने के लिए बूटस्ट्रैप तंत्र प्रदान करता है। एक एप्लिकेशन में आमतौर पर कई कार्यात्मक मॉड्यूल होते हैं। AppModule
को app.module.ts
फ़ाइल में परिभाषित किया गया है।
Angular Router
NgModule एक सेवा प्रदान करता है जो आपको अपने एप्लिकेशन में विभिन्न एप्लिकेशन राज्यों और दृश्य पदानुक्रमों के बीच एक नेविगेशन पथ परिभाषित करने की अनुमति देता है। RouterModule
को app-routing.module.ts
फ़ाइल में परिभाषित किया गया है।
डेटा या लॉजिक के लिए जो किसी विशिष्ट दृश्य से संबंधित नहीं है, और जिसे आप घटकों के बीच साझा करना चाहते हैं, आप एक सेवा वर्ग बनाते हैं। एक सेवा वर्ग परिभाषा के तुरंत पहले @Injectable()
डेकोरेटर होता है। डेकोरेटर मेटाडेटा प्रदान करता है जो अन्य प्रदाताओं को आपकी कक्षा में निर्भरता के रूप में इंजेक्ट करने की अनुमति देता है। निर्भरता इंजेक्शन (DI) आपको अपने घटक वर्गों को पतला और कुशल बनाए रखने की अनुमति देता है। वे सर्वर से डेटा नहीं लाते, उपयोगकर्ता इनपुट को मान्य नहीं करते, या सीधे कंसोल में लॉग नहीं करते; वे ऐसी कार्यों को सेवाओं को सौंपते हैं।
Sourcemap configuration
Angular फ्रेमवर्क TypeScript फ़ाइलों को JavaScript कोड में अनुवाद करता है tsconfig.json
विकल्पों का पालन करते हुए और फिर angular.json
कॉन्फ़िगरेशन के साथ एक प्रोजेक्ट बनाता है। angular.json
फ़ाइल को देखते हुए, हमने एक विकल्प देखा जो एक sourcemap को सक्षम या अक्षम करने के लिए है। Angular दस्तावेज़ के अनुसार, डिफ़ॉल्ट कॉन्फ़िगरेशन में स्क्रिप्ट के लिए एक sourcemap फ़ाइल सक्षम होती है और यह डिफ़ॉल्ट रूप से छिपी नहीं होती है:
"sourceMap": {
"scripts": true,
"styles": true,
"vendor": false,
"hidden": false
}
आम तौर पर, sourcemap फ़ाइलों का उपयोग डिबगिंग उद्देश्यों के लिए किया जाता है क्योंकि ये उत्पन्न फ़ाइलों को उनके मूल फ़ाइलों से मैप करती हैं। इसलिए, इन्हें उत्पादन वातावरण में उपयोग करने की सिफारिश नहीं की जाती है। यदि sourcemaps सक्षम हैं, तो यह पठनीयता में सुधार करता है और Angular प्रोजेक्ट की मूल स्थिति को दोहराकर फ़ाइल विश्लेषण में मदद करता है। हालाँकि, यदि इन्हें अक्षम किया गया है, तो एक समीक्षक अभी भी एंटी-सुरक्षा पैटर्न की खोज करके एक संकलित JavaScript फ़ाइल का मैन्युअल रूप से विश्लेषण कर सकता है।
इसके अलावा, एक संकलित JavaScript फ़ाइल Angular प्रोजेक्ट के साथ ब्राउज़र डेवलपर टूल्स → Sources (या Debugger और Sources) → [id].main.js में पाई जा सकती है। सक्षम विकल्पों के आधार पर, इस फ़ाइल के अंत में निम्नलिखित पंक्ति हो सकती है //# sourceMappingURL=[id].main.js.map
या यह नहीं हो सकती, यदि hidden विकल्प true पर सेट है। फिर भी, यदि scripts के लिए sourcemap अक्षम है, तो परीक्षण अधिक जटिल हो जाता है, और हम फ़ाइल प्राप्त नहीं कर सकते। इसके अलावा, प्रोजेक्ट निर्माण के दौरान sourcemap को सक्षम किया जा सकता है जैसे ng build --source-map
।
डेटा बाइंडिंग
बाइंडिंग उस प्रक्रिया को संदर्भित करती है जिसमें एक घटक और इसके संबंधित दृश्य के बीच संचार होता है। इसका उपयोग Angular ढांचे के लिए डेटा को स्थानांतरित करने के लिए किया जाता है। डेटा को विभिन्न तरीकों से पास किया जा सकता है, जैसे कि घटनाओं, इंटरपोलेशन, गुणों, या दो-तरफा बाइंडिंग तंत्र के माध्यम से। इसके अलावा, डेटा को संबंधित घटकों (माता-पिता-शिशु संबंध) और दो अप्रासंगिक घटकों के बीच सेवा सुविधा का उपयोग करके भी साझा किया जा सकता है।
हम डेटा प्रवाह द्वारा बाइंडिंग को वर्गीकृत कर सकते हैं:
- डेटा स्रोत से दृश्य लक्ष्य (जिसमें interpolation, properties, attributes, classes और styles शामिल हैं); इसे टेम्पलेट में
[]
या{{}}
का उपयोग करके लागू किया जा सकता है; - दृश्य लक्ष्य से डेटा स्रोत (जिसमें events शामिल हैं); इसे टेम्पलेट में
()
का उपयोग करके लागू किया जा सकता है; - दो-तरफा; इसे टेम्पलेट में
[()]
का उपयोग करके लागू किया जा सकता है।
बाइंडिंग को गुणों, घटनाओं, और विशेषताओं पर, साथ ही स्रोत निर्देशिका के किसी भी सार्वजनिक सदस्य पर बुलाया जा सकता है:
TYPE | TARGET | EXAMPLES |
---|---|---|
Property | Element property, Component property, Directive property | <img [alt]="hero.name" [src]="heroImageUrl"> |
Event | Element event, Component event, Directive event | <button type="button" (click)="onSave()">Save |
Two-way | Event and property | <input [(ngModel)]="name"> |
Attribute | Attribute (the exception) | <button type="button" [attr.aria-label]="help">help |
Class | class property | <div [class.special]="isSpecial">Special |
Style | style property | <button type="button" [style.color]="isSpecial ? 'red' : 'green'"> |
Angular सुरक्षा मॉडल
Angular का डिज़ाइन डिफ़ॉल्ट रूप से सभी डेटा को एन्कोडिंग या सैनिटाइजेशन करता है, जिससे Angular प्रोजेक्ट में XSS कमजोरियों को खोजने और शोषण करना अधिक कठिन हो जाता है। डेटा हैंडलिंग के लिए दो अलग-अलग परिदृश्य हैं:
- इंटरपोलेशन या
{{user_input}}
- संदर्भ-संवेदनशील एन्कोडिंग करता है और उपयोगकर्ता इनपुट को पाठ के रूप में व्याख्या करता है;
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
//app.component.html
{{test}}
परिणाम: <script>alert(1)</script><h1>test</h1>
2. गुणों, विशेषताओं, कक्षाओं और शैलियों के लिए बाइंडिंग या [attribute]="user_input"
- प्रदान किए गए सुरक्षा संदर्भ के आधार पर सैनिटाइजेशन करता है।
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
//app.component.html
<div [innerHtml]="test"></div>
परिणाम: <div><h1>test</h1></div>
SecurityContext
के 6 प्रकार हैं:
None
;HTML
का उपयोग तब किया जाता है, जब मान को HTML के रूप में व्याख्या किया जाता है;STYLE
का उपयोग तब किया जाता है, जब CSS कोstyle
गुण में बाइंड किया जाता है;URL
का उपयोग URL गुणों के लिए किया जाता है, जैसे<a href>
;SCRIPT
का उपयोग JavaScript कोड के लिए किया जाता है;RESOURCE_URL
एक URL के रूप में जो कोड के रूप में लोड और निष्पादित किया जाता है, उदाहरण के लिए,<script src>
में।
कमजोरियाँ
सुरक्षा ट्रस्ट विधियों को बायपास करना
Angular अपनी डिफ़ॉल्ट सैनिटाइजेशन प्रक्रिया को बायपास करने के लिए विधियों की एक सूची पेश करता है और यह इंगित करता है कि एक मान को एक विशिष्ट संदर्भ में सुरक्षित रूप से उपयोग किया जा सकता है, जैसे कि निम्नलिखित पांच उदाहरणों में:
bypassSecurityTrustUrl
का उपयोग यह इंगित करने के लिए किया जाता है कि दिया गया मान एक सुरक्षित शैली URL है:
//app.component.ts
this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()');
//app.component.html
<a class="e2e-trusted-url" [href]="trustedUrl">Click me</a>
//result
<a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Click me</a>
bypassSecurityTrustResourceUrl
का उपयोग यह इंगित करने के लिए किया जाता है कि दिया गया मान एक सुरक्षित संसाधन URL है:
//app.component.ts
this.trustedResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl("https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png");
//app.component.html
<iframe [src]="trustedResourceUrl"></iframe>
//result
<img _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png">
bypassSecurityTrustHtml
का उपयोग यह इंगित करने के लिए किया जाता है कि दिया गया मान सुरक्षित HTML है। ध्यान दें कि इस तरह DOM पेड़ मेंscript
तत्वों को डालने से उन्हें संलग्न JavaScript कोड को निष्पादित नहीं करने का कारण बनता है, क्योंकि ये तत्व DOM पेड़ में कैसे जोड़े जाते हैं।
//app.component.ts
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml("<h1>html tag</h1><svg onclick=\"alert('bypassSecurityTrustHtml')\" style=display:block>blah</svg>");
//app.component.html
<p style="border:solid" [innerHtml]="trustedHtml"></p>
//result
<h1>html tag</h1>
<svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg>
bypassSecurityTrustScript
का उपयोग यह इंगित करने के लिए किया जाता है कि दिया गया मान सुरक्षित JavaScript है। हालाँकि, हमने इसके व्यवहार को अप्रत्याशित पाया, क्योंकि हम इस विधि का उपयोग करके टेम्पलेट में JS कोड को निष्पादित नहीं कर सके।
//app.component.ts
this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')");
//app.component.html
<script [innerHtml]="trustedScript"></script>
//result
-
bypassSecurityTrustStyle
का उपयोग यह इंगित करने के लिए किया जाता है कि दिया गया मान सुरक्षित CSS है। निम्नलिखित उदाहरण CSS इंजेक्शन को दर्शाता है:
//app.component.ts
this.trustedStyle = this.sanitizer.bypassSecurityTrustStyle('background-image: url(https://example.com/exfil/a)');
//app.component.html
<input type="password" name="pwd" value="01234" [style]="trustedStyle">
//result
Request URL: GET example.com/exfil/a
Angular एक sanitize
विधि प्रदान करता है जो डेटा को प्रदर्शित करने से पहले सैनिटाइज करता है। यह विधि प्रदान किए गए सुरक्षा संदर्भ का उपयोग करती है और इनपुट को तदनुसार साफ करती है। हालाँकि, विशिष्ट डेटा और संदर्भ के लिए सही सुरक्षा संदर्भ का उपयोग करना महत्वपूर्ण है। उदाहरण के लिए, HTML सामग्री पर SecurityContext.URL
के साथ सैनिटाइज़र लागू करने से खतरनाक HTML मानों के खिलाफ सुरक्षा नहीं मिलती है। ऐसे परिदृश्यों में, सुरक्षा संदर्भ का दुरुपयोग XSS कमजोरियों का कारण बन सकता है।
HTML इंजेक्शन
यह कमजोरी तब होती है जब उपयोगकर्ता इनपुट को innerHTML
, outerHTML
, या iframe
srcdoc
में से किसी एक तीन गुणों से बाइंड किया जाता है। जबकि इन विशेषताओं के लिए बाइंडिंग HTML को जैसा है वैसा व्याख्या करती है, इनपुट को SecurityContext.HTML
का उपयोग करके सैनिटाइज किया जाता है। इस प्रकार, HTML इंजेक्शन संभव है, लेकिन क्रॉस-साइट स्क्रिप्टिंग (XSS) नहीं है।
innerHTML
का उपयोग करने का उदाहरण:
//app.component.ts
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent{
//define a variable with user input
test = "<script>alert(1)</script><h1>test</h1>";
}
//app.component.html
<div [innerHTML]="test"></div>
The result is <div><h1>test</h1></div>
.
Template injection
Client-Side Rendering (CSR)
Angular टेम्पलेट्स का उपयोग करके पृष्ठों को गतिशील रूप से बनाने के लिए टेम्पलेट्स का लाभ उठाता है। यह दृष्टिकोण Angular को मूल्यांकन करने के लिए टेम्पलेट अभिव्यक्तियों को डबल कर्ली ब्रैकेट्स ({{}}
) के भीतर संलग्न करने की आवश्यकता होती है। इस तरह, फ्रेमवर्क अतिरिक्त कार्यक्षमता प्रदान करता है। उदाहरण के लिए, एक टेम्पलेट जैसे {{1+1}}
2 के रूप में प्रदर्शित होगा।
आमतौर पर, Angular उपयोगकर्ता इनपुट को बचाता है जिसे टेम्पलेट अभिव्यक्तियों के साथ भ्रमित किया जा सकता है (जैसे, `< > ' " `\ जैसे वर्ण)। इसका मतलब है कि इस प्रतिबंध को दरकिनार करने के लिए अतिरिक्त कदम उठाने की आवश्यकता होती है, जैसे कि जावास्क्रिप्ट स्ट्रिंग ऑब्जेक्ट बनाने वाली फ़ंक्शंस का उपयोग करना ताकि ब्लैकलिस्टेड वर्णों का उपयोग न किया जा सके। हालाँकि, इसे प्राप्त करने के लिए, हमें Angular संदर्भ, इसकी विशेषताओं और चर पर विचार करना होगा। इसलिए, एक टेम्पलेट इंजेक्शन हमला इस प्रकार दिखाई दे सकता है:
//app.component.ts
const _userInput = '{{constructor.constructor(\'alert(1)\'()}}'
@Component({
selector: 'app-root',
template: '<h1>title</h1>' + _userInput
})
जैसा कि ऊपर दिखाया गया है: constructor
ऑब्जेक्ट constructor
प्रॉपर्टी के दायरे को संदर्भित करता है, जिससे हमें स्ट्रिंग कंस्ट्रक्टर को कॉल करने और मनमाने कोड को निष्पादित करने की अनुमति मिलती है।
सर्वर-साइड रेंडरिंग (SSR)
CSR के विपरीत, जो ब्राउज़र के DOM में होता है, Angular Universal टेम्पलेट फ़ाइलों के SSR के लिए जिम्मेदार है। ये फ़ाइलें फिर उपयोगकर्ता को भेजी जाती हैं। इस भिन्नता के बावजूद, Angular Universal SSR सुरक्षा को बढ़ाने के लिए CSR में उपयोग किए जाने वाले समान सैनिटाइजेशन तंत्रों को लागू करता है। SSR में एक टेम्पलेट इंजेक्शन कमजोरियों को CSR की तरह ही पहचाना जा सकता है, क्योंकि उपयोग की जाने वाली टेम्पलेट भाषा समान है।
बेशक, Pug और Handlebars जैसे थर्ड-पार्टी टेम्पलेट इंजनों का उपयोग करते समय नई टेम्पलेट इंजेक्शन कमजोरियों को पेश करने की संभावना भी है।
XSS
DOM इंटरफेस
जैसा कि पहले कहा गया था, हम Document इंटरफेस का उपयोग करके सीधे DOM तक पहुँच सकते हैं। यदि उपयोगकर्ता इनपुट को पहले से मान्य नहीं किया गया है, तो यह क्रॉस-साइट स्क्रिप्टिंग (XSS) कमजोरियों की ओर ले जा सकता है।
हमने नीचे दिए गए उदाहरणों में document.write()
और document.createElement()
विधियों का उपयोग किया:
//app.component.ts 1
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
document.open();
document.write("<script>alert(document.domain)</script>");
document.close();
}
}
//app.component.ts 2
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
var d = document.createElement('script');
var y = document.createTextNode("alert(1)");
d.appendChild(y);
document.body.appendChild(d);
}
}
//app.component.ts 3
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
var a = document.createElement('img');
a.src='1';
a.setAttribute('onerror','alert(1)');
document.body.appendChild(a);
}
}
Angular classes
Angular में DOM तत्वों के साथ काम करने के लिए कुछ क्लासेस हैं: ElementRef
, Renderer2
, Location
और Document
। अंतिम दो क्लासेस का विस्तृत विवरण Open redirects अनुभाग में दिया गया है। पहले दो के बीच मुख्य अंतर यह है कि Renderer2
API DOM तत्व और कंपोनेंट कोड के बीच एक एब्स्ट्रैक्शन की परत प्रदान करता है, जबकि ElementRef
केवल तत्व का संदर्भ रखता है। इसलिए, Angular दस्तावेज़ के अनुसार, ElementRef
API का उपयोग केवल अंतिम उपाय के रूप में किया जाना चाहिए जब DOM तक सीधी पहुँच की आवश्यकता हो।
ElementRef
मेंnativeElement
प्रॉपर्टी होती है, जिसका उपयोग DOM तत्वों को संशोधित करने के लिए किया जा सकता है। हालाँकि,nativeElement
का अनुचित उपयोग XSS इंजेक्शन भेद्यता का परिणाम बन सकता है, जैसा कि नीचे दिखाया गया है:
//app.component.ts
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
...
constructor(private elementRef: ElementRef) {
const s = document.createElement('script');
s.type = 'text/javascript';
s.textContent = 'alert("Hello World")';
this.elementRef.nativeElement.appendChild(s);
}
}
- हालाँकि
Renderer2
API प्रदान करता है जिसे सुरक्षित रूप से उपयोग किया जा सकता है, भले ही मूल तत्वों तक सीधी पहुँच का समर्थन न हो, फिर भी इसमें कुछ सुरक्षा दोष हैं।Renderer2
के साथ,setAttribute()
विधि का उपयोग करके HTML तत्व पर विशेषताएँ सेट करना संभव है, जिसमें कोई XSS रोकथाम तंत्र नहीं है।
//app.component.ts
import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public constructor (
private renderer2: Renderer2
){}
@ViewChild("img") img!: ElementRef;
addAttribute(){
this.renderer2.setAttribute(this.img.nativeElement, 'src', '1');
this.renderer2.setAttribute(this.img.nativeElement, 'onerror', 'alert(1)');
}
}
//app.component.html
<img #img>
<button (click)="setAttribute()">Click me!</button>
- DOM तत्व की प्रॉपर्टी सेट करने के लिए, आप
Renderer2.setProperty()
विधि का उपयोग कर सकते हैं और XSS हमले को ट्रिगर कर सकते हैं:
//app.component.ts
import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public constructor (
private renderer2: Renderer2
){}
@ViewChild("img") img!: ElementRef;
setProperty(){
this.renderer2.setProperty(this.img.nativeElement, 'innerHTML', '<img src=1 onerror=alert(1)>');
}
}
//app.component.html
<a #a></a>
<button (click)="setProperty()">Click me!</button>
हमारे शोध के दौरान, हमने XSS और CSS इंजेक्शन के संबंध में अन्य Renderer2
विधियों जैसे setStyle()
, createComment()
, और setValue()
के व्यवहार की भी जांच की। हालाँकि, हम इन विधियों के लिए कोई मान्य हमलावर वेक्टर नहीं ढूंढ सके।
jQuery
jQuery एक तेज, छोटा और फीचर-समृद्ध JavaScript लाइब्रेरी है जिसे Angular प्रोजेक्ट में HTML DOM ऑब्जेक्ट्स के साथ हेरफेर करने में मदद के लिए उपयोग किया जा सकता है। हालाँकि, जैसा कि ज्ञात है, इस लाइब्रेरी की विधियों का उपयोग XSS भेद्यता प्राप्त करने के लिए किया जा सकता है। Angular प्रोजेक्ट्स में कुछ कमजोर jQuery विधियों के शोषण पर चर्चा करने के लिए, हमने इस उपखंड को जोड़ा।
html()
विधि सेट के पहले तत्व की HTML सामग्री प्राप्त करती है या हर मिलान किए गए तत्व की HTML सामग्री सेट करती है। हालाँकि, डिज़ाइन के अनुसार, कोई भी jQuery कंस्ट्रक्टर या विधि जो HTML स्ट्रिंग स्वीकार करती है, संभावित रूप से कोड निष्पादित कर सकती है। यह<script>
टैग के इंजेक्शन या कोड निष्पादित करने वाले HTML विशेषताओं के उपयोग के माध्यम से हो सकता है जैसा कि उदाहरण में दिखाया गया है।
//app.component.ts
import { Component, OnInit } from '@angular/core';
import * as $ from 'jquery';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit
{
ngOnInit()
{
$("button").on("click", function()
{
$("p").html("<script>alert(1)</script>");
});
}
}
//app.component.html
<button>Click me</button>
<p>some text here</p>
jQuery.parseHTML()
विधि स्ट्रिंग को DOM नोड्स के सेट में परिवर्तित करने के लिए मूल विधियों का उपयोग करती है, जिसे फिर दस्तावेज़ में डाला जा सकता है।
jQuery.parseHTML(data [, context ] [, keepScripts ])
जैसा कि पहले उल्लेख किया गया है, अधिकांश jQuery APIs जो HTML स्ट्रिंग स्वीकार करते हैं, HTML में शामिल स्क्रिप्ट चलाएंगे। jQuery.parseHTML()
विधि पार्स की गई HTML में स्क्रिप्ट नहीं चलाती जब तक कि keepScripts
स्पष्ट रूप से true
न हो। हालाँकि, अधिकांश वातावरण में अप्रत्यक्ष रूप से स्क्रिप्ट निष्पादित करना संभव है; उदाहरण के लिए, <img onerror>
विशेषता के माध्यम से।
//app.component.ts
import { Component, OnInit } from '@angular/core';
import * as $ from 'jquery';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit
{
ngOnInit()
{
$("button").on("click", function()
{
var $palias = $("#palias"),
str = "<img src=1 onerror=alert(1)>",
html = $.parseHTML(str),
nodeNames = [];
$palias.append(html);
});
}
}
//app.component.html
<button>Click me</button>
<p id="palias">some text</p>
Open redirects
DOM interfaces
W3C दस्तावेज़ के अनुसार, window.location
और document.location
ऑब्जेक्ट्स को आधुनिक ब्राउज़रों में उपनाम के रूप में माना जाता है। यही कारण है कि उनके कुछ विधियों और प्रॉपर्टीज़ का समान कार्यान्वयन होता है, जो javascript://
स्कीमा हमलों के साथ एक ओपन रीडायरेक्ट और DOM XSS का कारण बन सकता है जैसा कि नीचे उल्लेख किया गया है।
window.location.href
(औरdocument.location.href
)
वर्तमान DOM स्थान ऑब्जेक्ट प्राप्त करने का मानक तरीका window.location
का उपयोग करना है। इसका उपयोग ब्राउज़र को एक नए पृष्ठ पर रीडायरेक्ट करने के लिए भी किया जा सकता है। परिणामस्वरूप, इस ऑब्जेक्ट पर नियंत्रण होने से हमें एक ओपन रीडायरेक्ट भेद्यता का शोषण करने की अनुमति मिलती है।
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.href = "https://google.com/about"
}
}
//app.component.html
<button type="button" (click)="goToUrl()">Click me!</button>
शोषण प्रक्रिया निम्नलिखित परिदृश्यों के लिए समान है।
window.location.assign()
(औरdocument.location.assign()
)
यह विधि विंडो को निर्दिष्ट URL पर दस्तावेज़ लोड और प्रदर्शित करने का कारण बनती है। यदि हमारे पास इस विधि पर नियंत्रण है, तो यह ओपन रीडायरेक्ट हमले के लिए एक सिंक हो सकता है।
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.assign("https://google.com/about")
}
}
window.location.replace()
(औरdocument.location.replace()
)
यह विधि वर्तमान संसाधन को प्रदान किए गए URL पर वाले से बदल देती है।
यह assign()
विधि से भिन्न है कि window.location.replace()
का उपयोग करने के बाद, वर्तमान पृष्ठ सत्र इतिहास में नहीं बचाया जाएगा। हालाँकि, जब हमारे पास इस विधि पर नियंत्रण होता है, तो ओपन रीडायरेक्ट भेद्यता का शोषण करना भी संभव है।
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.replace("http://google.com/about")
}
}
window.open()
window.open()
विधि एक URL लेती है और इसे एक नए या मौजूदा टैब या विंडो में लोड करती है। इस विधि पर नियंत्रण होने से XSS या ओपन रीडायरेक्ट भेद्यता को ट्रिगर करने का अवसर भी मिल सकता है।
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.open("https://google.com/about", "_blank")
}
}
Angular classes
- Angular दस्तावेज़ के अनुसार, Angular
Document
DOM दस्तावेज़ के समान है, जिसका अर्थ है कि Angular में क्लाइंट-साइड भेद्यताओं का शोषण करने के लिए DOM दस्तावेज़ के लिए सामान्य वेक्टरों का उपयोग करना संभव है।Document.location
प्रॉपर्टीज़ और विधियाँ सफल ओपन रीडायरेक्ट हमलों के लिए सिंक हो सकती हैं जैसा कि उदाहरण में दिखाया गया है:
//app.component.ts
import { Component, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(@Inject(DOCUMENT) private document: Document) { }
goToUrl(): void {
this.document.location.href = 'https://google.com/about';
}
}
//app.component.html
<button type="button" (click)="goToUrl()">Click me!</button>
- शोध चरण के दौरान, हमने ओपन रीडायरेक्ट भेद्यताओं के लिए Angular
Location
क्लास की भी समीक्षा की, लेकिन कोई मान्य वेक्टर नहीं मिला।Location
एक Angular सेवा है जिसका उपयोग एप्लिकेशन वर्तमान URL के साथ बातचीत करने के लिए कर सकते हैं। इस सेवा में दिए गए URL को संशोधित करने के लिए कई विधियाँ हैं -go()
,replaceState()
, औरprepareExternalUrl()
। हालाँकि, हम उन्हें बाहरी डोमेन पर रीडायरेक्ट करने के लिए उपयोग नहीं कर सकते। उदाहरण के लिए:
//app.component.ts
import { Component, Inject } from '@angular/core';
import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}],
})
export class AppComponent {
location: Location;
constructor(location: Location) {
this.location = location;
}
goToUrl(): void {
console.log(this.location.go("http://google.com/about"));
}
}
परिणाम: http://localhost:4200/http://google.com/about
- Angular
Router
क्लास मुख्य रूप से उसी डोमेन के भीतर नेविगेट करने के लिए उपयोग की जाती है और एप्लिकेशन में कोई अतिरिक्त भेद्यताएँ नहीं लाती है:
//app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'https://google.com', pathMatch: 'full' }]
परिणाम: http://localhost:4200/https:
निम्नलिखित विधियाँ भी डोमेन के दायरे के भीतर नेविगेट करती हैं:
const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ]
this.router.navigate(['PATH'])
this.router.navigateByUrl('URL')
References
- Angular
- Angular Security: The Definitive Guide (Part 1)
- Angular Security: The Definitive Guide (Part 2)
- Angular Security: The Definitive Guide (Part 3)
- Angular Security: Checklist
- Workspace and project file structure
- Introduction to components and templates
- Source map configuration
- Binding syntax
- Angular Context: Easy Data-Binding for Nested Component Trees and the Router Outlet
- Sanitization and security contexts
- GitHub - angular/dom_security_schema.ts
- XSS in Angular and AngularJS
- Angular Universal
- DOM XSS
- Angular ElementRef
- Angular Renderer2
- Renderer2 Example: Manipulating DOM in Angular - TekTutorialsHub
- jQuery API Documentation
- How To Use jQuery With Angular (When You Absolutely Have To)
- Angular Document
- Angular Location
- Angular Router