Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:55:36 +08:00
commit cc90ad1792
20 changed files with 8932 additions and 0 deletions

681
references/security.md Normal file
View File

@@ -0,0 +1,681 @@
# SAPUI5 Security Guide
**Source**: Official SAP SAPUI5 Documentation
**Documentation**: [https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps](https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps)
**Last Updated**: 2025-11-21
---
## Overview
Security is critical for enterprise applications. SAPUI5 provides built-in security features, but developers must use them correctly.
**Security Principles**:
1. **Never trust user input**
2. **Use framework security features**
3. **Keep framework updated**
4. **Follow secure coding practices**
5. **Test for vulnerabilities**
**Documentation**: [https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps](https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps) (search: security, secure-programming)
---
## Cross-Site Scripting (XSS) Prevention
### Overview
XSS occurs when attackers inject malicious scripts into web pages viewed by other users.
**SAPUI5 Protection**: Automatic output encoding in data binding and controls.
### Automatic Protection
**Data Binding** (Safe):
```xml
<!-- Automatically HTML-encoded -->
<Text text="{/userName}"/>
<Input value="{/userInput}"/>
```
**Control Properties** (Safe):
```javascript
// Automatically encoded
oText.setText(sUserInput);
oButton.setText(sUserInput);
```
### Dangerous Patterns
**innerHTML** (NEVER USE):
```javascript
// DANGEROUS - DO NOT USE
this.byId("myDiv").getDomRef().innerHTML = sUserInput;
// SAFE - Use data binding or setText
this.byId("myText").setText(sUserInput);
```
**jQuery HTML manipulation** (Avoid):
```javascript
// DANGEROUS
this.$("#myDiv").html(sUserInput);
// SAFE
this.byId("myText").setText(sUserInput);
```
### HTML Content
If HTML content is necessary, use `sap.ui.core.HTML` with sanitization:
```javascript
sap.ui.require([
"sap/ui/core/HTML",
"sap/base/security/sanitizeHTML"
], function(HTML, sanitizeHTML) {
// Sanitize HTML
var sSafeHTML = sanitizeHTML(sUnsafeHTML, {
uriRewriter: function(sUrl) {
// Whitelist URLs
if (sUrl.startsWith("[https://trusted.com/](https://trusted.com/)")) {
return sUrl;
}
return "";
}
});
// Create HTML control
var oHTML = new HTML({
content: sSafeHTML,
sanitizeContent: true
});
});
```
### URL Validation
**Validate URLs** before using:
```javascript
sap.ui.require([
"sap/base/security/URLWhitelist"
], function(URLWhitelist) {
// Add trusted domains
URLWhitelist.add("https", "trusted.com");
URLWhitelist.add("https", "*.mycompany.com");
// Validate URL
if (URLWhitelist.validate(sUrl)) {
// URL is safe
window.open(sUrl);
} else {
// URL not trusted
MessageBox.error("Invalid URL");
}
});
```
**Never use** `javascript:` URLs:
```javascript
// DANGEROUS
<Link href="javascript:alert('XSS')"/>
// SAFE
<Link press=".onLinkPress"/>
```
---
## Content Security Policy (CSP)
### Overview
CSP prevents XSS by controlling which resources can be loaded and executed.
**SAPUI5 Support**: Framework is CSP-compliant.
### Configuration
**Server-Side** (Recommended):
```
Content-Security-Policy: default-src 'self';
script-src 'self' [https://sapui5.hana.ondemand.com;](https://sapui5.hana.ondemand.com;)
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
font-src 'self' data:;
connect-src 'self' [https://api.mybackend.com;](https://api.mybackend.com;)
```
**Meta Tag** (Alternative):
```html
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' [https://sapui5.hana.ondemand.com;](https://sapui5.hana.ondemand.com;)
style-src 'self' 'unsafe-inline';">
```
### SAPUI5 CSP Requirements
**Required Directives**:
- `script-src`: Allow SAPUI5 CDN or local resources
- `style-src 'unsafe-inline'`: Required for dynamic styles
- `font-src`: Allow icon fonts
- `img-src data:`: Allow data URIs for images
**Nonce Support** (Better than 'unsafe-inline'):
```html
<meta http-equiv="Content-Security-Policy"
content="style-src 'self' 'nonce-{{random}}'; script-src 'self' 'nonce-{{random}}'">
<script nonce="{{random}}" src="resources/sap-ui-core.js"></script>
```
### Testing CSP
1. Enable CSP in development
2. Check browser console for violations
3. Adjust policy as needed
4. Test all application features
**Common Violations**:
- Inline scripts (use external files)
- `eval()` calls (refactor code)
- Inline event handlers (use addEventListener)
---
## Clickjacking Prevention
### Overview
Clickjacking tricks users into clicking on hidden elements by overlaying malicious content on legitimate pages.
### Frame Options
**X-Frame-Options Header** (Server-Side):
```
X-Frame-Options: DENY
```
Or allow same origin:
```
X-Frame-Options: SAMEORIGIN
```
**CSP Frame Ancestors**:
```
Content-Security-Policy: frame-ancestors 'none';
```
Or specify allowed origins:
```
Content-Security-Policy: frame-ancestors 'self' [https://trusted.com;](https://trusted.com;)
```
### Framebuster Script
For legacy browsers:
```html
<script>
if (top !== self) {
top.location = self.location;
}
</script>
```
---
## Authentication & Authorization
### Authentication
**Never store credentials** in client-side code:
```javascript
// DANGEROUS - DO NOT DO THIS
var sPassword = "hardcoded123";
// SAFE - Use server-side authentication
fetch("/api/login", {
method: "POST",
credentials: "include",
body: JSON.stringify({ username, password })
});
```
**Use Secure Tokens**:
```javascript
// Store token securely (httpOnly cookie preferred)
// If using localStorage, encrypt sensitive data
```
### Authorization
**Check permissions** server-side:
```javascript
// Client-side (UI only, not security)
if (this.hasPermission("delete")) {
this.byId("deleteButton").setVisible(true);
}
// Server-side (actual security check)
DELETE /api/products/123
Authorization: Bearer <token>
```
**Never rely** on client-side checks for security:
```javascript
// This is UI convenience, NOT security
if (oUser.role === "admin") {
this.showAdminPanel();
}
// Real security happens on server
```
---
## Secure Data Transmission
### HTTPS
**Always use HTTPS** in production:
```javascript
// manifest.json
{
"sap.app": {
"dataSources": {
"mainService": {
"uri": "[https://api.mycompany.com/odata/",](https://api.mycompany.com/odata/",) // HTTPS
"type": "OData"
}
}
}
}
```
**Redirect HTTP to HTTPS** (Server-Side):
```
HTTP/1.1 301 Moved Permanently
Location: [https://myapp.com/](https://myapp.com/)
```
### CORS
**Configure CORS** properly on backend:
```
Access-Control-Allow-Origin: [https://myapp.com](https://myapp.com)
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
```
**Never use** `*` with credentials:
```
# DANGEROUS
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
```
---
## CSRF Protection
### Overview
Cross-Site Request Forgery tricks authenticated users into performing unwanted actions.
### CSRF Tokens
**OData V2**:
SAPUI5 automatically handles CSRF tokens for OData V2 models:
```javascript
// Automatic CSRF token handling
oModel.create("/Products", oData, {
success: function() {
// Token automatically included
}
});
```
**Custom AJAX**:
```javascript
fetch("/api/action", {
method: "POST",
headers: {
"X-CSRF-Token": await this.fetchCSRFToken()
},
credentials: "include",
body: JSON.stringify(data)
});
fetchCSRFToken: async function() {
const response = await fetch("/api/csrf-token", {
method: "HEAD",
credentials: "include"
});
return response.headers.get("X-CSRF-Token");
}
```
---
## Input Validation
### Client-Side Validation
**Validate format**, not security:
```javascript
onEmailChange: function(oEvent) {
var sEmail = oEvent.getParameter("value");
var oInput = oEvent.getSource();
// Basic format validation (UI convenience)
var bValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(sEmail);
oInput.setValueState(bValid ? "None" : "Error");
oInput.setValueStateText(bValid ? "" : "Invalid email format");
// Real validation happens on server
}
```
**Use Data Types**:
```xml
<Input
value="{
path: '/email',
type: 'sap.ui.model.type.String',
constraints: {
maxLength: 100,
search: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
}
}"/>
```
### Server-Side Validation
**Always validate** on server:
```javascript
// Client sends data
oModel.create("/Products", {
name: sName,
price: fPrice
}, {
success: function() {
// Server has validated input
},
error: function(oError) {
// Server rejected invalid input
MessageBox.error("Validation failed");
}
});
```
---
## Secure Storage
### Sensitive Data
**Never store** sensitive data in localStorage or sessionStorage:
```javascript
// DANGEROUS
localStorage.setItem("password", sPassword);
localStorage.setItem("apiKey", sApiKey);
// SAFE - Use secure httpOnly cookies (server-side)
// Or short-lived memory-only storage
```
### Session Management
**Use server-side sessions**:
```javascript
// Login
fetch("/api/login", {
method: "POST",
credentials: "include", // Send cookies
body: JSON.stringify({ username, password })
});
// Requests automatically include session cookie
fetch("/api/data", {
credentials: "include"
});
// Logout
fetch("/api/logout", {
method: "POST",
credentials: "include"
});
```
---
## SQL Injection Prevention
### OData Services
**Use parameterized queries** in backend:
```javascript
// Client-side (safe - OData handles escaping)
oModel.read("/Products", {
filters: [
new Filter("Name", FilterOperator.EQ, sUserInput)
]
});
// Backend must use parameterized queries
// DO NOT concatenate SQL strings
```
---
## Secure Configuration
### Manifest.json
**Don't expose** sensitive information:
```json
// DANGEROUS
{
"sap.app": {
"dataSources": {
"mainService": {
"uri": "[https://api.mycompany.com/odata/?apikey=secret123"](https://api.mycompany.com/odata/?apikey=secret123")
}
}
}
}
// SAFE
{
"sap.app": {
"dataSources": {
"mainService": {
"uri": "[https://api.mycompany.com/odata/"](https://api.mycompany.com/odata/")
// API key sent via server-side proxy
}
}
}
}
```
### Environment Variables
**Use environment-specific** configuration:
```javascript
// Build-time replacement
var API_URL = "#{API_URL}#"; // Replaced during build
// Or runtime configuration
fetch("/config.json").then(config => {
// Use config.apiUrl
});
```
---
## Security Testing
### Manual Testing
1. **XSS Testing**:
- Input `<script>alert('XSS')</script>`
- Input `<img src=x onerror=alert('XSS')>`
- Verify automatic encoding
2. **CSRF Testing**:
- Attempt cross-origin requests
- Verify token validation
3. **Authentication**:
- Test without credentials
- Test with expired tokens
- Test privilege escalation
### Automated Testing
**OWASP ZAP**:
```bash
# Scan application
zap-cli quick-scan -s xss,sqli [http://localhost:8080](http://localhost:8080)
```
**Retire.js** (Check for vulnerable libraries):
```bash
npm install -g retire
retire --js --path webapp/
```
---
## Security Checklist
### XSS Prevention
- [ ] Use data binding for user input
- [ ] Never use innerHTML
- [ ] Sanitize HTML content if needed
- [ ] Validate URLs before use
- [ ] No javascript: URLs
### CSP
- [ ] CSP header configured
- [ ] Application works with CSP enabled
- [ ] No CSP violations in console
- [ ] script-src and style-src configured
### Clickjacking
- [ ] X-Frame-Options header set
- [ ] frame-ancestors CSP directive set
- [ ] Framebuster script if needed
### Authentication
- [ ] No credentials in code
- [ ] Secure token storage
- [ ] HTTPS only in production
- [ ] Session timeout implemented
### Authorization
- [ ] Server-side permission checks
- [ ] Client-side checks for UI only
- [ ] Role-based access control
- [ ] Least privilege principle
### Data Transmission
- [ ] HTTPS everywhere
- [ ] CORS properly configured
- [ ] No sensitive data in URLs
- [ ] Secure cookie flags (HttpOnly, Secure)
### Input Validation
- [ ] Client-side format validation
- [ ] Server-side security validation
- [ ] Data types with constraints
- [ ] Whitelist, not blacklist
### Secure Storage
- [ ] No sensitive data in localStorage
- [ ] Session management server-side
- [ ] httpOnly cookies for tokens
---
## Common Vulnerabilities
### 1. Reflected XSS
**Vulnerable**:
```javascript
var sSearch = new URLSearchParams(window.location.search).get("q");
this.byId("searchField").getDomRef().innerHTML = sSearch;
```
**Fixed**:
```javascript
var sSearch = new URLSearchParams(window.location.search).get("q");
this.byId("searchField").setValue(sSearch);
```
### 2. DOM-based XSS
**Vulnerable**:
```javascript
var sUrl = location.hash.substring(1);
window.location = sUrl;
```
**Fixed**:
```javascript
sap.ui.require(["sap/base/security/URLWhitelist"], function(URLWhitelist) {
var sUrl = location.hash.substring(1);
if (URLWhitelist.validate(sUrl)) {
window.location = sUrl;
}
});
```
### 3. Insecure Direct Object Reference
**Vulnerable**:
```javascript
// User can modify ID in URL
var sId = oRouter.getParameter("id");
oModel.read("/Orders(" + sId + ")"); // Access to any order
```
**Fixed**:
```javascript
// Server checks if user has access to this order
var sId = oRouter.getParameter("id");
oModel.read("/Orders(" + sId + ")", {
// Server validates: user can only access their own orders
});
```
---
## Official Documentation
- **Security**: [https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps](https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps) (search: security, secure-programming)
- **XSS Prevention**: [https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps](https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps) (search: cross-site-scripting)
- **CSP**: [https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps](https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps) (search: content-security-policy)
- **URL Whitelist**: [https://sapui5.hana.ondemand.com/#/api/sap.base.security.URLWhitelist](https://sapui5.hana.ondemand.com/#/api/sap.base.security.URLWhitelist)
- **OWASP Top 10**: [https://owasp.org/www-project-top-ten/](https://owasp.org/www-project-top-ten/)
---
**Note**: This document covers security best practices for SAPUI5. Security is not optional - it must be built into every application from the start. Always follow the principle of defense in depth.