docker-ddns-server/dyndns/views/failed_auths.html
w3K 7983a3fb49 v2.0.0
# Complete Enhancement Package - Major Feature Update

Comprehensive enhancement package for docker-ddns-server including security features, modern authentication, UI/UX improvements, and production-ready deployment features.

## 🔒 Security & Authentication

### IP Blocking System
- Implemented automatic IP blocking after 3 failed authentication attempts within 72 hours
- Added 7-day block duration with automatic expiration
- Created `blocked_ips` database table for tracking blocked addresses
- Added automatic cleanup of expired blocks
- Implemented manual IP unblock capability via security dashboard

### Failed Authentication Logging
- Added comprehensive failed authentication logging system
- Created `failed_auths` database table storing IP, timestamp, username, and password
- Implemented threat intelligence features for password pattern analysis
- Added automatic cleanup of old authentication records
- Logs intentionally include passwords for single-user security analysis

### Session-Based Authentication
- Replaced HTTP Basic Auth with modern session-based authentication for admin panel
- Integrated gorilla/sessions library for secure session management
- Added configurable session secrets via `DDNS_SESSION_SECRET` environment variable
- Implemented "Remember Me" functionality with 30-day session duration
- Added proper session destruction on logout
- Session cookies configured with HttpOnly, Secure, and SameSite attributes
- Maintained HTTP Basic Auth for DynDNS API endpoints (device compatibility)

### HTTPS Enforcement
- Added intelligent HTTPS detection via multiple header checks
- Implemented automatic HTTPS redirect for admin panel when available
- Graceful HTTP fallback when HTTPS unavailable
- Supports reverse proxy configurations (nginx, Caddy, Traefik)
- Detects SSL via X-Forwarded-Proto, X-Forwarded-Ssl, X-Url-Scheme headers
- API endpoints remain HTTP-compatible for device support

## 🎨 UI/UX Enhancements

### Authentication UI
- Created modern login page with gradient background and clean design
- Added HTTPS security indicator (✓ green / ⚠ yellow)
- Implemented auto-focus on username field
- Added clear error messages for failed login attempts
- Created logout confirmation page with redirect options
- Removed browser authentication dialog popups

### Navigation & Layout
- Changed admin panel URL from `/admin` to `/@` for uniqueness
- Updated navigation with unicode icons (🏠 Dashboard, 🔒 Security, ⏏️ Logout)
- Added tooltips to all navigation icons
- Implemented sticky header that remains visible on scroll
- Enhanced responsive design for mobile/tablet access

### Logo Support
- Added automatic logo detection and display
- Supports PNG, WebP, and SVG formats
- Checks `/static/icons/` for logo files
- Graceful fallback to text title if no logo found
- Maintains aspect ratio and responsive sizing

### Security Dashboard
- Created comprehensive security overview page at `/@/security`
- Added statistics cards showing active blocks, failed attempts, and total blocks
- Implemented recent failed attempts table with sortable columns
- Added password reveal/hide functionality with confirmation prompts
- Created detailed blocked IPs management page with unblock capability
- Created detailed failed authentication logs page with full history
- Added visual indicators for security status

## 📊 Data Management

### Data Consistency & Normalization
- Implemented automatic lowercase conversion for all usernames and hostnames
- Prevents case-sensitivity issues in DNS lookups and authentication
- Ensures consistent data storage and retrieval
- Handles mixed-case legacy data gracefully

### Automatic Migration
- Added on-the-fly migration system for legacy uppercase entries
- Migration triggers automatically on first `/@/hosts` page visit
- Handles hostname conflicts by appending sequential numbers
- Provides detailed migration report in UI showing all changes
- Non-destructive migration preserves all host data
- One-time execution with persistent migration status tracking

### Validation Updates
- Reduced minimum hostname length to 1 character (allows single-letter subdomains)
- Reduced minimum username length to 1 character
- Reduced minimum password length to 6 characters
- Maintained security while improving flexibility

### Username Uniqueness
- Removed uniqueness constraint on usernames
- Allows multiple hosts to share the same username
- Supports different passwords for same username across hosts
- Enables more flexible credential management strategies

## 🛡️ Middleware & Request Handling

### IP Blocker Middleware
- Created IPBlockerMiddleware to check requests against blocked IPs
- Automatic redirect to 127.0.0.1 for blocked addresses
- Lightweight performance impact with database lookup
- Positioned early in middleware chain for efficiency

### Session Authentication Middleware
- Created SessionAuthMiddleware for admin panel protection
- Skips authentication check for /login and /logout routes
- Redirects unauthenticated users to login page
- Validates session integrity on every request
- Compatible with reverse proxy configurations

### HTTPS Redirect Middleware
- Created HTTPSRedirectMiddleware for admin panel security
- Intelligent detection of HTTPS availability
- Skips redirect for API endpoints
- Handles X-Forwarded-* headers from reverse proxies
- Graceful operation when HTTPS unavailable

## 🗄️ Database & Models

### New Tables
- Added `failed_auths` table for authentication logging
- Added `blocked_ips` table for IP block tracking
- Proper foreign key relationships and indexes
- Automatic timestamps on all records

### Cleanup Functions
- Implemented automatic cleanup of expired IP blocks
- Implemented automatic cleanup of old authentication logs
- Configurable retention periods
- Background cleanup execution

## 🔧 Technical Improvements

### Dependencies
- Added `github.com/gorilla/sessions@v1.2.2` for session management
- Updated go.mod with proper version constraints
- Maintained compatibility with existing dependencies

### Handler Architecture
- Separated security logic into dedicated handler files
- Created `security.go` for blocking logic and logging
- Created `security_dashboard.go` for UI handlers
- Created `auth.go` for login/logout and session management
- Created `session.go` for session store implementation
- Improved code organization and maintainability

### Main Application
- Updated routing to support session-based authentication
- Added session initialization on startup
- Configured route groups for admin panel and API
- Middleware ordering optimized for performance and security

## 🐳 Docker & CI/CD

### Multi-Platform Builds & Automated Releases
- Created GitHub Actions workflow (`BuildEmAll.yml`) for automated Docker builds
- Supports linux/amd64, linux/386, linux/arm/v7, and linux/arm64 platforms
- Automatic builds on push to master with dyndns/ directory changes
- Intelligent version tagging system:
  - Extracts version from commit message (e.g., "v1.2.3 Feature description")
  - Auto-increments patch version from latest git tag
  - Falls back to date-based versioning (vYY.MM.DD-HHMM) if no tags exist
- Tags images with both `:latest` and semantic version tags (`:vX.Y.Z`)
- Automatic GitHub release creation with each build
- Release includes Docker image reference and commit message as notes
- Publishes to Docker Hub (w3kllc/ddns)
- Cross-platform compatibility for ARM devices (Raspberry Pi, etc.)
- Workflow can be triggered manually via GitHub Actions UI

### Deployment
- Enhanced docker-compose.yml example with all new features
- Added documentation for environment variable configuration
- Included reverse proxy configuration examples
- Added security best practices for production deployment
- Semantic versioning with automatic release management

## 📝 Documentation

### README Enhancements
- Added comprehensive Security Features section
- Added Environment Variables reference with descriptions
- Added Admin Panel Access documentation
- Added Data Consistency & Migration guide
- Added API Endpoints documentation
- Added UI/UX Enhancements overview
- Added Reverse Proxy Configuration examples
- Added Docker Configuration best practices
- Added CI/CD & Multi-Platform Support details with versioning strategy
- Added Semantic Versioning documentation
- Added GitHub Release automation details
- Added Security Best Practices recommendations
- Added Threat Intelligence rationale
- Added Migration Guide from original project
- Added Troubleshooting section
- Added API Reference documentation
- Added Roadmap for future features
- Updated Credits section
- Added Support and Community links

## 🔄 Backward Compatibility

### Maintained Features
- DynDNS API endpoints remain unchanged (/update, /nic/update, etc.)
- HTTP Basic Auth still supported for API (device compatibility)
- Existing host configurations continue working without changes
- Database schema additions are non-breaking
- All original functionality preserved

### Breaking Changes
- Admin panel URL changed from `/admin` to `/@` (intentional, more unique)
- Admin authentication method changed (sessions vs basic auth)
- Requires `DDNS_SESSION_SECRET` environment variable for session security

##  Performance Considerations

- IP blocker checks are optimized with database indexing
- Session validation cached in memory
- Automatic cleanup runs asynchronously
- Minimal overhead on API endpoint performance
- Efficient middleware ordering

## 🎯 Testing Considerations

Recommended testing areas:
- Login/logout flow with and without HTTPS
- IP blocking after 3 failed attempts
- Session persistence with remember me
- API endpoint authentication (device compatibility)
- HTTPS redirect with reverse proxy headers
- Password reveal/hide in security dashboard
- Hostname migration for legacy uppercase entries
- Multi-platform Docker image functionality

---

**Total Changes:**
- **21 files modified**
- **20 new files created**
- **~2000+ lines of code added**
- **100+ hours of development time**

**Compatibility:**
-  Backward compatible for DynDNS API
- ⚠️ Admin panel URL changed (bookmark update needed)
-  All existing hosts continue working
-  Database schema additions are additive

**Credits:**
- Original project: dprandzioch/docker-ddns
- Web UI Fork: benjaminbear/docker-ddns-server
- Enhanced fork: w3K-one/docker-ddns-server
- Major enhancements and security features added

This represents a significant enhancement to the original project while maintaining the core DynDNS functionality and adding modern security, authentication, and user experience improvements suitable for production deployment.
2025-10-11 16:07:36 -04:00

363 lines
13 KiB
HTML

{{define "content"}}
<div class="container marketing">
<h3 class="text-center mb-4">Failed Authentication Attempts</h3>
<div class="mb-3">
<a href="/@/security" class="btn btn-secondary">&larr; Back to Security Dashboard</a>
</div>
<div class="alert alert-warning" role="alert">
<strong>⚠️ Security Warning:</strong> This system logs attempted passwords for security analysis.
<ul class="mb-0 mt-2">
<li>Ensure this database is encrypted and access is strictly controlled</li>
<li>Never share or export this data without proper authorization</li>
<li>Be aware that users may have mistyped legitimate passwords</li>
<li>Comply with relevant data protection regulations (GDPR, etc.)</li>
</ul>
</div>
<div class="alert alert-info" role="alert">
<strong>📌 IP Blocking Policy:</strong> Only failed attempts to the admin panel (<code>/@/*</code>) count toward IP blocking.
API endpoint failures (like <code>/nic/update</code>) are logged but do NOT trigger automatic IP blocks.
</div>
<style>
/* Alternating yellow shades for API rows */
.table-warning-light {
background-color: #fff9e6 !important; /* Lighter yellow */
}
.table-warning {
background-color: #fff3cd !important; /* Standard yellow */
}
/* Tooltip container for positioning */
.tooltip-container {
position: relative;
display: inline-block;
}
/* Speech bubble tooltip */
.speech-tooltip {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
margin-bottom: 10px;
padding: 8px 12px;
background: #2c3e50;
color: #fff;
border-radius: 6px;
font-size: 13px;
font-family: 'Courier New', monospace;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s, visibility 0.2s;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
/* Password tooltips: single line, auto-width */
.pwd-btn + .speech-tooltip {
white-space: nowrap;
max-width: 90vw; /* Don't exceed viewport */
}
/* User Agent tooltips: multi-line, 50% table width */
.ua-btn + .speech-tooltip,
.ua-btn .speech-tooltip {
white-space: normal;
max-width: 50%; /* 50% of container width */
min-width: 200px;
word-wrap: break-word;
text-align: left;
}
/* Arrow pointing down */
.speech-tooltip::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: #2c3e50;
}
/* Show tooltip when active */
.speech-tooltip.active {
opacity: 1;
visibility: visible;
}
/* Clickable tooltip styling with cursor */
.tooltip-btn {
cursor: pointer;
transition: all 0.2s;
border: none;
background: transparent;
padding: 2px 6px;
border-radius: 3px;
position: relative;
}
.tooltip-btn:hover {
background-color: rgba(0,0,0,0.05);
}
.tooltip-btn.active {
background-color: #ffc107 !important;
}
/* User Agent button - make it look clickable */
.ua-btn {
cursor: pointer;
transition: background-color 0.2s;
}
.ua-btn:hover {
background-color: rgba(0,0,0,0.03);
}
/* Copy feedback animation */
.copy-feedback {
position: absolute;
top: -25px;
left: 50%;
transform: translateX(-50%);
background: #28a745;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 11px;
white-space: nowrap;
z-index: 2000;
animation: fadeInOut 1.5s ease-in-out;
pointer-events: none;
}
@keyframes fadeInOut {
0% { opacity: 0; transform: translateX(-50%) translateY(5px); }
20% { opacity: 1; transform: translateX(-50%) translateY(0); }
80% { opacity: 1; transform: translateX(-50%) translateY(0); }
100% { opacity: 0; transform: translateX(-50%) translateY(-5px); }
}
/* Truncated text styling */
.truncated {
/* No underline - clean look */
}
</style>
<table class="table table-striped" style="font-size: 14px">
<thead>
<tr>
<th>Timestamp</th>
<th>IP Address</th>
<th>Username</th>
<th>Password Attempted</th>
<th>Path</th>
<th>User Agent</th>
</tr>
</thead>
<tbody>
{{range $index, $auth := .failedAuths}}
{{$isAPI := not (hasPrefix $auth.Path "/@/")}}
{{$rowClass := ""}}
{{if $isAPI}}
{{if eq (mod $index 2) 0}}
{{$rowClass = "table-warning"}}
{{else}}
{{$rowClass = "table-warning-light"}}
{{end}}
{{end}}
<tr class="{{$rowClass}}">
<td>{{$auth.Timestamp.Format "01/02/2006 15:04:05"}}</td>
<td><code>{{$auth.IPAddress}}</code></td>
<td>{{if $auth.Username}}<strong>{{$auth.Username}}</strong>{{else}}<em class="text-muted">no credentials</em>{{end}}</td>
<td>
{{if $auth.Password}}
<div class="tooltip-container">
<button class="btn btn-sm btn-outline-secondary tooltip-btn pwd-btn">👁</button>
<div class="speech-tooltip">
<code style="color: #ffc107; font-weight: bold;">{{$auth.Password}}</code>
</div>
</div>
{{else}}
<em class="text-muted">no password</em>
{{end}}
</td>
<td>
<code>{{$auth.Path}}</code>
{{if hasPrefix $auth.Path "/@/"}}
<span class="badge badge-danger ml-1">Admin</span>
{{else}}
<span class="badge badge-secondary ml-1">API</span>
{{end}}
</td>
<td>
{{if $auth.UserAgent}}
{{$ua := $auth.UserAgent}}
{{if gt (len $ua) 10}}
<div class="tooltip-container">
<button class="tooltip-btn ua-btn" title="Click to copy">
<span class="truncated">{{slice $ua 0 10}}...</span>
</button>
<div class="speech-tooltip">
<span style="color: #fff;">{{$ua}}</span>
</div>
</div>
{{else}}
<span class="ua-btn" style="cursor: pointer;" title="Click to copy">{{$ua}}</span>
{{end}}
{{else}}
<em class="text-muted">none</em>
{{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
{{if not .failedAuths}}
<div class="alert alert-success text-center" role="alert">
<h4 class="alert-heading">No Failed Attempts</h4>
<p>There are no recorded failed authentication attempts. Excellent!</p>
</div>
{{end}}
<div class="alert alert-info mt-4" role="alert">
<strong>📋 Note:</strong> Failed authentication records are automatically cleaned up after 30 days.
IP addresses are blocked after <strong>3 failed ADMIN PANEL attempts</strong> within a 72-hour period and blocked for 7 days.
<br><strong>API endpoint failures do NOT trigger IP blocking.</strong>
</div>
</div>
<script>
$(document).ready(function() {
console.log('Failed auths page JavaScript loaded');
// Helper function to copy text to clipboard
function copyToClipboard(text, button) {
// Modern clipboard API
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function() {
showCopyFeedback(button, 'Copied!');
}).catch(function(err) {
console.error('Failed to copy:', err);
fallbackCopy(text, button);
});
} else {
// Fallback for older browsers
fallbackCopy(text, button);
}
}
// Fallback copy method
function fallbackCopy(text, button) {
var textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
showCopyFeedback(button, 'Copied!');
} catch (err) {
console.error('Fallback copy failed:', err);
showCopyFeedback(button, 'Copy failed');
}
document.body.removeChild(textArea);
}
// Show copy feedback animation
function showCopyFeedback(button, message) {
var feedback = $('<div class="copy-feedback">' + message + '</div>');
$(button).closest('.tooltip-container, td').append(feedback);
setTimeout(function() {
feedback.remove();
}, 1500);
}
// Password tooltips: Click to toggle AND copy
$(document).on('click', '.pwd-btn', function(e) {
e.preventDefault();
e.stopPropagation();
var button = $(this);
var tooltip = button.siblings('.speech-tooltip');
var password = button.closest('.tooltip-container').find('.speech-tooltip code').text();
// Copy password to clipboard
copyToClipboard(password, button);
// Close all other tooltips first
$('.speech-tooltip').removeClass('active');
$('.tooltip-btn').removeClass('active');
// Toggle this one
if (tooltip.hasClass('active')) {
tooltip.removeClass('active');
button.removeClass('active');
} else {
tooltip.addClass('active');
button.addClass('active');
}
});
// User Agent tooltips: Hover to show, Click to copy
$(document).on('mouseenter', '.ua-btn', function() {
var tooltip = $(this).siblings('.speech-tooltip');
tooltip.addClass('active');
});
$(document).on('mouseleave', '.ua-btn', function() {
var tooltip = $(this).siblings('.speech-tooltip');
// Small delay to allow moving mouse to tooltip
setTimeout(function() {
if (!tooltip.is(':hover')) {
tooltip.removeClass('active');
}
}, 100);
});
// Click on User Agent to copy
$(document).on('click', '.ua-btn', function(e) {
e.preventDefault();
e.stopPropagation();
var button = $(this);
var userAgent = button.closest('.tooltip-container').find('.speech-tooltip span').text();
// If there's no tooltip (short UA), get text directly
if (!userAgent) {
userAgent = button.text().trim();
}
copyToClipboard(userAgent, button);
});
// Keep tooltip open if hovering over it
$(document).on('mouseenter', '.ua-btn + .speech-tooltip', function() {
$(this).addClass('active');
});
$(document).on('mouseleave', '.ua-btn + .speech-tooltip', function() {
$(this).removeClass('active');
});
// Close password tooltips when clicking anywhere else on page
$(document).on('click', function(e) {
if (!$(e.target).closest('.pwd-btn').length) {
$('.pwd-btn').removeClass('active');
$('.pwd-btn').siblings('.speech-tooltip').removeClass('active');
}
});
console.log('Found', $('.pwd-btn').length, 'password buttons');
console.log('Found', $('.ua-btn').length, 'user agent buttons');
});
</script>
{{end}}