![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/.cursor-server/data/User/History/-20c2f9e4/ |
<?php
/**
* Security Documentation Page
* Private page explaining our MP3 protection measures
* Requires authentication to view
*/
require_once 'config/database.php';
require_once 'includes/translations.php';
session_start();
$user_id = $_SESSION['user_id'] ?? null;
// Require authentication to view security documentation
if (!$user_id) {
header('Location: /auth/login.php?redirect=' . urlencode('/security.php'));
exit;
}
// Get user info
$pdo = getDBConnection();
$stmt = $pdo->prepare("SELECT name, plan FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
$currentLang = getCurrentLanguage();
$pageTitle = t('security.title');
?>
<!DOCTYPE html>
<html lang="<?= $currentLang ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($pageTitle) ?> - Sound Studio Pro</title>
<link rel="stylesheet" href="/assets/css/main.css">
<style>
body {
padding-top: 80px;
min-height: 100vh;
}
.security-container {
max-width: 1200px;
margin: 0 auto;
padding: var(--space-xl) var(--space-md);
}
.security-header {
text-align: center;
margin-bottom: var(--space-2xl);
padding: var(--space-2xl);
background: var(--gradient-primary);
border-radius: var(--radius-lg);
color: var(--text-primary);
box-shadow: var(--shadow-heavy);
position: relative;
overflow: hidden;
}
.security-header::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
animation: pulse 4s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 0.5; }
50% { transform: scale(1.1); opacity: 0.8; }
}
.security-header h1 {
margin: 0 0 var(--space-md) 0;
font-size: clamp(2rem, 5vw, 3rem);
font-weight: 800;
position: relative;
z-index: 1;
}
.security-header p {
font-size: clamp(1rem, 2vw, 1.25rem);
opacity: 0.95;
margin: 0;
position: relative;
z-index: 1;
}
.security-section {
background: var(--bg-card);
backdrop-filter: blur(10px);
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: var(--space-xl);
margin-bottom: var(--space-lg);
box-shadow: var(--shadow-medium);
transition: var(--transition-normal);
}
.security-section:hover {
border-color: var(--border-accent);
box-shadow: var(--shadow-glow);
}
.security-section h2 {
color: var(--primary);
margin-top: 0;
margin-bottom: var(--space-md);
font-size: clamp(1.5rem, 3vw, 2rem);
display: flex;
align-items: center;
gap: var(--space-sm);
}
.security-section h3 {
color: var(--secondary);
margin-top: var(--space-lg);
margin-bottom: var(--space-sm);
font-size: clamp(1.2rem, 2.5vw, 1.5rem);
}
.security-icon {
font-size: 1.8rem;
filter: drop-shadow(0 0 10px rgba(102, 126, 234, 0.5));
}
.protection-layer {
background: var(--bg-secondary);
border-left: 4px solid var(--primary);
padding: var(--space-lg);
margin: var(--space-md) 0;
border-radius: var(--radius-sm);
box-shadow: var(--shadow-light);
}
.protection-layer h4 {
color: var(--primary);
margin-top: 0;
margin-bottom: var(--space-sm);
font-size: 1.2rem;
}
.protection-layer ul {
margin: var(--space-sm) 0;
padding-left: var(--space-lg);
list-style: none;
}
.protection-layer ul li {
margin: var(--space-sm) 0;
line-height: 1.8;
color: var(--text-secondary);
position: relative;
padding-left: var(--space-md);
}
.protection-layer ul li::before {
content: '✓';
position: absolute;
left: 0;
color: var(--primary);
font-weight: bold;
}
.protection-layer ul li strong {
color: var(--text-primary);
}
.code-example {
background: var(--bg-primary);
border: 1px solid var(--border-light);
color: var(--text-secondary);
padding: var(--space-lg);
border-radius: var(--radius-sm);
overflow-x: auto;
font-family: var(--font-mono);
font-size: 0.9rem;
margin: var(--space-md) 0;
box-shadow: var(--shadow-light);
}
.code-example code {
color: var(--accent);
}
.security-badge {
display: inline-block;
background: var(--gradient-primary);
color: var(--text-primary);
padding: var(--space-xs) var(--space-md);
border-radius: var(--radius-full);
font-size: 0.85rem;
font-weight: 600;
margin-left: var(--space-sm);
box-shadow: var(--shadow-light);
}
.warning-badge {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
}
.info-box {
background: rgba(79, 172, 254, 0.1);
border-left: 4px solid var(--accent);
padding: var(--space-lg);
margin: var(--space-md) 0;
border-radius: var(--radius-sm);
box-shadow: var(--shadow-light);
}
.info-box strong {
color: var(--accent);
}
.comparison-table {
width: 100%;
border-collapse: collapse;
margin: var(--space-md) 0;
background: var(--bg-secondary);
border-radius: var(--radius-sm);
overflow: hidden;
box-shadow: var(--shadow-light);
}
.comparison-table th,
.comparison-table td {
padding: var(--space-md);
text-align: left;
border-bottom: 1px solid var(--border-light);
}
.comparison-table th {
background: var(--gradient-primary);
color: var(--text-primary);
font-weight: 600;
text-transform: uppercase;
font-size: 0.85rem;
letter-spacing: 0.5px;
}
.comparison-table td {
color: var(--text-secondary);
}
.comparison-table tr:last-child td {
border-bottom: none;
}
.comparison-table tr:hover {
background: var(--bg-tertiary);
}
.checkmark {
color: #10b981;
font-weight: bold;
font-size: 1.2rem;
}
.xmark {
color: #ef4444;
font-weight: bold;
font-size: 1.2rem;
}
.security-section ol {
margin: var(--space-md) 0;
padding-left: var(--space-xl);
color: var(--text-secondary);
}
.security-section ol li {
margin: var(--space-sm) 0;
line-height: 1.8;
}
.security-section p {
color: var(--text-secondary);
line-height: 1.8;
}
.security-footer {
text-align: center;
background: var(--gradient-primary);
color: var(--text-primary);
margin-top: var(--space-2xl);
padding: var(--space-2xl);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-heavy);
}
.security-footer h2 {
color: var(--text-primary);
margin-bottom: var(--space-md);
}
.security-footer p {
color: var(--text-primary);
opacity: 0.95;
}
@media (max-width: 768px) {
.security-container {
padding: var(--space-md);
}
.security-section {
padding: var(--space-md);
}
.comparison-table {
font-size: 0.85rem;
}
.comparison-table th,
.comparison-table td {
padding: var(--space-sm);
}
}
</style>
</head>
<body>
<?php include 'includes/header_new.php'; ?>
<div class="security-container">
<div class="security-header">
<h1>🔒 <?= t('security.title') ?></h1>
<p><?= t('security.subtitle') ?></p>
</div>
<!-- Overview Section -->
<div class="security-section">
<h2><span class="security-icon">🛡️</span> <?= t('security.overview.title') ?></h2>
<p><?= t('security.overview.desc') ?></p>
<div class="info-box">
<strong><?= t('security.private_docs') ?></strong> <?= t('security.private_docs_desc') ?>
</div>
</div>
<!-- Layer 1: Token-Based Authentication -->
<div class="security-section">
<h2><span class="security-icon">🔑</span> <?= t('security.layer1.title') ?></h2>
<div class="protection-layer">
<h4><?= t('security.layer1.hmac') ?></h4>
<p><?= t('security.layer1.desc') ?></p>
<ul>
<li><strong><?= t('security.layer1.track_id') ?></strong></li>
<li><strong><?= t('security.layer1.variation') ?></strong></li>
<li><strong><?= t('security.layer1.expiration') ?></strong></li>
<li><strong><?= t('security.layer1.user_context') ?></strong></li>
<li><strong><?= t('security.layer1.secret') ?></strong></li>
</ul>
</div>
<h3><?= t('security.layer1.how_works') ?></h3>
<ol>
<li><?= t('security.layer1.step1') ?></li>
<li><?= t('security.layer1.step2') ?></li>
<li><?= t('security.layer1.step3') ?></li>
<li><?= t('security.layer1.step4') ?></li>
<li><?= t('security.layer1.step5') ?></li>
</ol>
<div class="code-example">
// Token Generation (simplified)
$data = $trackId . '|' . $variationIndex . '|' . $expires . '|' . $userContext;
$signature = hash_hmac('sha256', $data, SECRET_KEY);
$token = substr($signature, 0, 16);
</div>
<div class="info-box">
<strong><?= t('security.layer1.protection') ?></strong> <?= t('security.layer1.protection_desc') ?>
</div>
</div>
<!-- Layer 2: Session Binding -->
<div class="security-section">
<h2><span class="security-icon">🔗</span> <?= t('security.layer2.title') ?></h2>
<div class="protection-layer">
<h4><?= t('security.layer2.binding') ?></h4>
<p><?= t('security.layer2.desc') ?></p>
<ul>
<li><strong><?= t('security.layer2.cross_browser') ?></strong></li>
<li><strong><?= t('security.layer2.cross_session') ?></strong></li>
<li><strong><?= t('security.layer2.impersonation') ?></strong></li>
<li><strong><?= t('security.layer2.guest') ?></strong></li>
</ul>
</div>
<h3><?= t('security.layer2.mechanism') ?></h3>
<p><?= t('security.layer2.mechanism_desc') ?></p>
<ul>
<li><strong><?= t('security.layer2.logged_in') ?></strong></li>
<li><strong><?= t('security.layer2.guest_users') ?></strong></li>
</ul>
<p><?= t('security.layer2.validate_desc') ?></p>
<div class="info-box">
<strong><?= t('security.layer2.protection') ?></strong> <?= t('security.layer2.protection_desc') ?>
</div>
</div>
<!-- Layer 3: Referrer Validation -->
<div class="security-section">
<h2><span class="security-icon">🚫</span> <?= t('security.layer3.title') ?></h2>
<div class="protection-layer">
<h4><?= t('security.layer3.strict') ?></h4>
<p><?= t('security.layer3.desc') ?></p>
<ul>
<li><strong><?= t('security.layer3.track') ?></strong></li>
<li><strong><?= t('security.layer3.community') ?></strong></li>
<li><strong><?= t('security.layer3.create') ?></strong></li>
<li><strong><?= t('security.layer3.radio') ?></strong></li>
</ul>
</div>
<h3><?= t('security.layer3.how_works') ?></h3>
<ol>
<li><?= t('security.layer3.step1') ?></li>
<li><?= t('security.layer3.step2') ?></li>
<li><?= t('security.layer3.step3') ?></li>
<li><?= t('security.layer3.step4') ?></li>
</ol>
<div class="comparison-table">
<thead>
<tr>
<th><?= t('security.layer3.table_method') ?></th>
<th><?= t('security.layer3.table_referrer') ?></th>
<th><?= t('security.layer3.table_result') ?></th>
</tr>
</thead>
<tbody>
<tr>
<td><?= t('security.layer3.table_click_track') ?></td>
<td>https://soundstudiopro.com/track.php?id=123</td>
<td><span class="checkmark"><?= t('security.layer3.table_allowed') ?></span></td>
</tr>
<tr>
<td><?= t('security.layer3.table_click_community') ?></td>
<td>https://soundstudiopro.com/community_fixed.php</td>
<td><span class="checkmark"><?= t('security.layer3.table_allowed') ?></span></td>
</tr>
<tr>
<td><?= t('security.layer3.table_paste') ?></td>
<td>None (direct access)</td>
<td><span class="xmark"><?= t('security.layer3.table_blocked') ?></span></td>
</tr>
<tr>
<td><?= t('security.layer3.table_share') ?></td>
<td>None or different domain</td>
<td><span class="xmark"><?= t('security.layer3.table_blocked') ?></span></td>
</tr>
</tbody>
</div>
<div class="info-box">
<strong><?= t('security.layer3.protection') ?></strong> <?= t('security.layer3.protection_desc') ?>
</div>
</div>
<!-- Layer 4: One-Time Use Tokens -->
<div class="security-section">
<h2><span class="security-icon">⏱️</span> Layer 4: One-Time Use Enforcement</h2>
<div class="protection-layer">
<h4>Strict Usage Limiting</h4>
<p>Tokens are tracked per session and have strict usage limits:</p>
<ul>
<li><strong>Max Uses:</strong> 1 use per token (no refreshes allowed)</li>
<li><strong>Session-Based Tracking:</strong> Usage is tracked in PHP session</li>
<li><strong>Immediate Consumption:</strong> Token is consumed on first page load</li>
<li><strong>Refresh Blocking:</strong> Any attempt to refresh or reload is blocked</li>
</ul>
</div>
<h3>Usage Tracking:</h3>
<p>The system tracks token usage in the user's session:</p>
<ul>
<li>When a token is first used (page load), it's marked as consumed</li>
<li>Subsequent requests with the same token are immediately rejected</li>
<li>Range requests (playback/seeking) don't consume additional uses - they're part of the same session</li>
<li>Token usage data is cleaned up automatically after expiration</li>
</ul>
<div class="info-box">
<strong>✅ Protection:</strong> Prevents URL sharing and reuse. Even if someone gets a valid token, they can only use it once. Refreshing the page or trying to access it again will fail.
</div>
</div>
<!-- Layer 5: Expiration -->
<div class="security-section">
<h2><span class="security-icon">⏰</span> Layer 5: Time-Based Expiration</h2>
<div class="protection-layer">
<h4>Short-Lived Tokens</h4>
<p>All tokens have a built-in expiration mechanism:</p>
<ul>
<li><strong>Expiration Time:</strong> 5 minutes (300 seconds) from generation</li>
<li><strong>Automatic Rejection:</strong> Expired tokens are immediately rejected</li>
<li><strong>No Extension:</strong> Tokens cannot be extended or renewed</li>
<li><strong>Fresh Tokens:</strong> New tokens are generated for each page load</li>
</ul>
</div>
<div class="info-box">
<strong>✅ Protection:</strong> Even if a token is intercepted, it becomes useless after 5 minutes. This limits the window of opportunity for any potential abuse.
</div>
</div>
<!-- Layer 6: Range Request Handling -->
<div class="security-section">
<h2><span class="security-icon">🎵</span> Layer 6: Smart Playback Handling</h2>
<div class="protection-layer">
<h4>Differentiated Request Types</h4>
<p>The system intelligently differentiates between different types of requests:</p>
<ul>
<li><strong>Page Loads:</strong> Initial GET requests (consume token use)</li>
<li><strong>Range Requests:</strong> Playback/seeking requests (don't consume additional uses)</li>
<li><strong>Seeking Support:</strong> Full HTTP Range request support for audio seeking</li>
<li><strong>Buffering:</strong> Multiple Range requests allowed for smooth playback</li>
</ul>
</div>
<h3>How It Works:</h3>
<p>When you click play:</p>
<ol>
<li><strong>Initial Load:</strong> Browser makes a GET request (consumes token use)</li>
<li><strong>Playback Starts:</strong> Audio player makes Range requests for streaming</li>
<li><strong>Seeking:</strong> User seeks to different position - new Range request</li>
<li><strong>Buffering:</strong> Player makes multiple Range requests for smooth playback</li>
</ol>
<p>All Range requests are allowed within the same session, ensuring smooth playback while maintaining security.</p>
<div class="info-box">
<strong>✅ User Experience:</strong> While maintaining strict security, the system ensures smooth playback, seeking, and buffering work perfectly. Users don't experience any interruptions during playback.
</div>
</div>
<!-- Security Comparison -->
<div class="security-section">
<h2><span class="security-icon">📊</span> Security Comparison</h2>
<div class="comparison-table">
<thead>
<tr>
<th>Attack Vector</th>
<th>Without Protection</th>
<th>With Our Protection</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Direct URL Sharing</strong></td>
<td><span class="xmark">❌ Vulnerable</span></td>
<td><span class="checkmark">✅ Blocked by Referrer Check</span></td>
</tr>
<tr>
<td><strong>Cross-Browser Access</strong></td>
<td><span class="xmark">❌ Vulnerable</span></td>
<td><span class="checkmark">✅ Blocked by Session Binding</span></td>
</tr>
<tr>
<td><strong>Token Reuse</strong></td>
<td><span class="xmark">❌ Vulnerable</span></td>
<td><span class="checkmark">✅ Blocked by One-Time Use</span></td>
</tr>
<tr>
<td><strong>URL Tampering</strong></td>
<td><span class="xmark">❌ Vulnerable</span></td>
<td><span class="checkmark">✅ Blocked by HMAC Signature</span></td>
</tr>
<tr>
<td><strong>Expired Token Use</strong></td>
<td><span class="xmark">❌ Vulnerable</span></td>
<td><span class="checkmark">✅ Blocked by Expiration Check</span></td>
</tr>
<tr>
<td><strong>Cross-Track Access</strong></td>
<td><span class="xmark">❌ Vulnerable</span></td>
<td><span class="checkmark">✅ Blocked by Track ID Binding</span></td>
</tr>
<tr>
<td><strong>Bulk Downloading</strong></td>
<td><span class="xmark">❌ Vulnerable</span></td>
<td><span class="checkmark">✅ Blocked by Multiple Layers</span></td>
</tr>
</tbody>
</div>
</div>
<!-- Technical Details -->
<div class="security-section">
<h2><span class="security-icon">🔧</span> Technical Implementation</h2>
<h3>Key Files:</h3>
<ul>
<li><strong>/utils/play_audio.php:</strong> Audio proxy endpoint with all security checks</li>
<li><strong>/utils/audio_token.php:</strong> Token generation and validation functions</li>
<li><strong>/track.php:</strong> Generates signed URLs for track pages</li>
<li><strong>/community_fixed.php:</strong> Generates signed URLs for community feed</li>
</ul>
<h3>Security Functions:</h3>
<ul>
<li><code>generateAudioToken()</code>: Creates HMAC-SHA256 signed tokens with user/session binding</li>
<li><code>validateAudioToken()</code>: Validates tokens with constant-time comparison</li>
<li><code>checkTokenUsage()</code>: Tracks and enforces usage limits</li>
<li><code>markTokenUsed()</code>: Records token consumption in session</li>
<li><code>getSignedAudioUrl()</code>: Generates complete signed URLs</li>
</ul>
<h3>Security Constants:</h3>
<ul>
<li><code>AUDIO_TOKEN_SECRET</code>: Unique per-installation secret key</li>
<li><code>AUDIO_TOKEN_EXPIRY</code>: 300 seconds (5 minutes)</li>
<li><code>AUDIO_TOKEN_MAX_USES</code>: 1 use per token</li>
</ul>
</div>
<!-- Best Practices -->
<div class="security-section">
<h2><span class="security-icon">💡</span> Best Practices for Artists</h2>
<div class="protection-layer">
<h4>What You Should Know:</h4>
<ul>
<li><strong>Your music is protected:</strong> All tracks are automatically protected by these security measures</li>
<li><strong>No additional action needed:</strong> Security is built-in and always active</li>
<li><strong>Public vs Private:</strong> Both public and private tracks use the same security measures</li>
<li><strong>Sharing is blocked:</strong> URLs cannot be shared or reused, even by the original user</li>
<li><strong>Playback is smooth:</strong> Security doesn't interfere with normal playback experience</li>
</ul>
</div>
<div class="info-box">
<strong>🎵 For Your Audience:</strong> Your listeners can play tracks normally through the website. The security is completely transparent to them - they won't notice any difference, but your music is fully protected.
</div>
</div>
<!-- Footer -->
<div class="security-footer">
<h2>🛡️ Your Music is Protected</h2>
<p style="font-size: 1.1rem; opacity: 0.95;">
Multiple layers of security work together to ensure your music cannot be stolen, shared, or accessed without authorization.
</p>
<p style="margin-top: var(--space-md); opacity: 0.9;">
<strong>Last Updated:</strong> <?= date('F j, Y') ?>
</p>
</div>
</div>
<?php include 'includes/footer_new.php'; ?>
</body>
</html>