Security measures and best practices implemented in the Package Script Writer application.
- Security Overview
- Security Headers Middleware
- HTTPS and HSTS
- Input Validation
- No Database = Reduced Attack Surface
- Dependency Security
- Best Practices
- Security Checklist
The application implements multiple security layers:
- Security Headers - Custom middleware adding protective headers
- HTTPS Enforcement - All traffic forced to HTTPS
- HSTS - HTTP Strict Transport Security enabled
- Input Validation - Client and server-side validation
- No Database - Stateless application reduces attack surface
- No Sensitive Data Storage - User credentials not persisted
Threat Model: Web application without authentication, focused on script generation
File: Middleware/SecurityHeadersMiddleware.cs
public class SecurityHeadersMiddleware
{
private readonly RequestDelegate _next;
public SecurityHeadersMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// Add security headers
context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("Referrer-Policy", "no-referrer");
context.Response.Headers.Add(
"Permissions-Policy",
"accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
);
await _next(context);
}
}app.UseMiddleware<SecurityHeadersMiddleware>();Purpose: Prevents clickjacking attacks by controlling iframe embedding.
Values:
DENY- No iframe embedding allowedSAMEORIGIN- Only same-origin iframes allowed (current setting)ALLOW-FROM uri- Specific origin allowed
Protection Against:
- Clickjacking attacks
- UI redressing attacks
- Malicious iframe embedding
Example Attack Prevented:
<!-- Attacker's site -->
<iframe src="https://psw.codeshare.co.uk"></iframe>
<!-- This iframe will be blocked -->Purpose: Prevents MIME-sniffing attacks.
Behavior: Forces browser to respect Content-Type header rather than guessing.
Protection Against:
- MIME confusion attacks
- Serving malicious content as safe content type
- XSS via file uploads
Example Attack Prevented:
Attacker uploads: malicious.txt (contains JavaScript)
Content-Type: text/plain
Without nosniff: Browser might execute as JavaScript
With nosniff: Browser treats as text only
Purpose: Prevents leaking referrer information to external sites.
Values:
no-referrer- Never send referrer (current setting)no-referrer-when-downgrade- Send referrer only for HTTPS → HTTPSorigin- Send only origin, not full URLsame-origin- Send referrer only to same origin
Protection Against:
- Information leakage via URL parameters
- Tracking across sites
- Privacy concerns
Example:
User at: https://psw.codeshare.co.uk?packages=secret-package
Clicks external link
Without policy: External site sees full URL with "secret-package"
With no-referrer: External site sees no referrer
Purpose: Disables browser features that aren't needed.
Current Policy:
accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
Features Disabled:
| Feature | Reason |
|---|---|
accelerometer |
Not needed for script generation |
camera |
No camera access required |
geolocation |
No location tracking |
gyroscope |
Not needed |
magnetometer |
Not needed |
microphone |
No audio features |
payment |
No payment processing |
usb |
No USB device access |
Benefits:
- Reduced attack surface
- Better user privacy
- Clear security posture
Middleware:
app.UseHttpsRedirection();Behavior:
- All HTTP requests → 301 redirect to HTTPS
- Forces secure connections
- Prevents man-in-the-middle attacks
Example:
Request: http://psw.codeshare.co.uk
Response: 301 Moved Permanently
Location: https://psw.codeshare.co.uk
Middleware (Production only):
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}Header Sent:
Strict-Transport-Security: max-age=2592000
Configuration (default):
max-age: 30 days (2,592,000 seconds)includeSubDomains: Not enabled by defaultpreload: Not enabled by default
Custom Configuration:
builder.Services.AddHsts(options =>
{
options.MaxAge = TimeSpan.FromDays(365);
options.IncludeSubDomains = true;
options.Preload = true;
});Behavior:
- Browser remembers to only use HTTPS
- Future requests automatically use HTTPS
- Protects against SSL stripping attacks
HSTS Preload List: To be included in browser's built-in HSTS list:
- Enable
includeSubDomains - Enable
preload - Set
max-age>= 31536000 (1 year) - Submit to: https://hstspreload.org/
HTML5 Validation:
<input type="email" required />
<input type="password" minlength="10" required />
<input type="text" maxlength="100" required />JavaScript Validation:
// Password strength check
function validatePassword(password) {
if (password.length < 10) {
return "Password must be at least 10 characters";
}
return null;
}
// Email format check
function validateEmail(email) {
var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}Data Annotations:
public class PackagesViewModel
{
[Required(ErrorMessage = "Project name is required")]
[MaxLength(100, ErrorMessage = "Project name too long")]
public string ProjectName { get; set; }
[EmailAddress(ErrorMessage = "Invalid email format")]
public string UserEmail { get; set; }
[MinLength(10, ErrorMessage = "Password must be at least 10 characters")]
public string UserPassword { get; set; }
}Model State Validation:
[HttpPost]
public IActionResult GenerateScript([FromBody] GeneratorApiRequest request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Process valid request
}| Field | Validation | Error Message |
|---|---|---|
ProjectName |
Required, MaxLength(100) | "Project name is required" / "Project name too long" |
UserEmail |
EmailAddress | "Invalid email format" |
UserPassword |
MinLength(10) | "Password must be at least 10 characters" |
TemplateName |
Required | "Template name is required" |
SolutionName |
Required (if CreateSolutionFile) | "Solution name required" |
No Database Means:
- ✅ No SQL injection vulnerabilities
- ✅ No database authentication attacks
- ✅ No stored XSS attacks
- ✅ No data breach risk (no user data stored)
- ✅ Simpler infrastructure
- ✅ Easier to scale horizontally
Data Sources:
- In-Memory Cache - Temporary storage only
- External APIs - Read-only access (NuGet.org, Umbraco Marketplace)
- Browser LocalStorage - Client-side only
User Credentials:
- Entered in form
- Sent to API
- Used in script generation
- Never stored or logged
Generated Scripts:
- Created on-demand
- Not persisted server-side
- Only visible to user
Configuration URLs:
- All state in query string
- No server-side session storage
- Shareable without authentication
Check for Vulnerabilities:
dotnet list package --vulnerableUpdate Packages:
dotnet add package <PackageName> --version <NewVersion>Current Dependencies:
- ASP.NET Core 10.0 (Microsoft-maintained, regular security updates)
- System.Text.Json (Microsoft-maintained)
- No third-party dependencies (minimal attack surface)
Tools:
- GitHub Dependabot - Automatic PRs for vulnerable dependencies
- Snyk - Continuous dependency monitoring
- OWASP Dependency-Check - Open-source scanner
Configuration (.github/dependabot.yml):
version: 2
updates:
- package-ecosystem: "nuget"
directory: "/src/PSW"
schedule:
interval: "weekly"| OWASP Risk | Mitigation |
|---|---|
| A01: Broken Access Control | No authentication required, public API |
| A02: Cryptographic Failures | HTTPS enforced, HSTS enabled |
| A03: Injection | No database, input validation on all fields |
| A04: Insecure Design | Stateless design, minimal data handling |
| A05: Security Misconfiguration | Security headers, proper error handling |
| A06: Vulnerable Components | Regular dependency updates, minimal dependencies |
| A07: Authentication Failures | Not applicable (no authentication) |
| A08: Software/Data Integrity | Subresource Integrity for CDN assets (if used) |
| A09: Logging Failures | Structured logging, no sensitive data logged |
| A10: SSRF | No user-controlled URLs to external resources |
Recommendation: Add CSP header for XSS protection.
Implementation:
context.Response.Headers.Add(
"Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https://marketplace.umbraco.com"
);Benefits:
- Prevents inline script execution (XSS protection)
- Controls resource loading
- Reports violations
Avoid String Concatenation:
// Bad
var command = "dotnet new " + templateName;
// Good
var command = $"dotnet new {templateName}";Use Parameterized Queries (if database added):
// Bad
var sql = $"SELECT * FROM Users WHERE Id = {userId}";
// Good
var sql = "SELECT * FROM Users WHERE Id = @UserId";
command.Parameters.AddWithValue("@UserId", userId);Validate All Input:
// Always validate, even if UI validates
if (string.IsNullOrWhiteSpace(model.ProjectName))
{
return BadRequest("Project name is required");
}Don't Leak Information:
// Bad - Exposes internal details
catch (Exception ex)
{
return BadRequest(ex.ToString());
}
// Good - Generic error message
catch (Exception ex)
{
_logger.LogError(ex, "Error generating script");
return StatusCode(500, "An error occurred while generating the script");
}Production Error Pages:
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}Never Log Sensitive Data:
// Bad
_logger.LogInformation("User password: {Password}", model.UserPassword);
// Good
_logger.LogInformation("User {Email} generated script for {ProjectName}",
model.UserEmail, model.ProjectName);Log Security Events:
- Failed validations
- Unusual request patterns
- API errors
- Cache clearing (admin action)
- HTTPS enabled with valid certificate
- HSTS enabled (
max-age >= 31536000) - Security headers middleware active
- Error handling configured (no stack traces in production)
- Logging configured (no sensitive data logged)
- Dependencies up to date (no known vulnerabilities)
- CSP header configured
- CORS configured (if API used cross-origin)
- Rate limiting implemented (if high traffic)
- Monitoring and alerting configured
Weekly:
- Check for dependency updates
- Review error logs for anomalies
Monthly:
- Review security headers (use securityheaders.com)
- Run vulnerability scan (OWASP ZAP, Burp Suite)
- Update dependencies
Quarterly:
- Security audit
- Penetration testing
- Review and update security policies
-
OWASP ZAP - Security scanner
zap-cli quick-scan https://psw.codeshare.co.uk
-
SecurityHeaders.com - Header checker Visit: https://securityheaders.com/?q=psw.codeshare.co.uk
-
SSL Labs - SSL/TLS tester Visit: https://www.ssllabs.com/ssltest/
-
Mozilla Observatory - Security assessment Visit: https://observatory.mozilla.org/
- Application Insights (Azure)
- Sentry - Error tracking
- Datadog - APM and security monitoring
- CloudFlare - DDoS protection and WAF
- Detect: Monitor logs for suspicious activity
- Contain: Isolate affected systems
- Eradicate: Remove threat
- Recover: Restore normal operations
- Learn: Post-mortem and improvements
Security Issues: Create a private security advisory on GitHub
Reporting Format:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Suggested mitigation
- Content Security Policy - Add CSP header
- Rate Limiting - Protect against abuse
- API Authentication - Optional API keys for high-volume users
- Subresource Integrity - For CDN assets
- Security Monitoring - Real-time threat detection
- WAF Integration - Web Application Firewall