Skip to content

CSRF Zaščita

2.5.x ✅ 4.0.x ✅

Napadi Cross-Site Request Forgery (CSRF) zavedejo uporabnike, da izvedejo neželena dejanja na spletnem mestu, kjer so overjeni. XOOPS zagotavlja vgrajeno CSRF zaščito prek razreda XoopsSecurity.

– Najboljše varnostne prakse – Obsežen varnostni vodnik

  • Input-Sanitization - MyTextSanitizer in validacija
  • SQL-Injection-Prevention - Varnostne prakse baze podatkov

Do napada CSRF pride, ko:

  1. Na vašem spletnem mestu XOOPS je uporabnik overjen
  2. Uporabnik obišče zlonamerno spletno stran
  3. Zlonamerno spletno mesto pošlje zahtevo vašemu spletnemu mestu XOOPS z uporabo uporabnikove seje.
  4. Vaše spletno mesto obdela zahtevo, kot da bi prišla od zakonitega uporabnika

XOOPS zagotavlja razred XoopsSecurity za zaščito pred napadi CSRF. Ta razred upravlja varnostne žetone, ki morajo biti vključeni v obrazce in preverjeni pri obdelavi zahtev.

Varnostni razred ustvari edinstvene žetone, ki so shranjeni v uporabnikovi seji in jih je treba vključiti v obrazce:

$security = new XoopsSecurity();
// Get token HTML input field
$tokenHTML = $security->getTokenHTML();
// Get just the token value
$tokenValue = $security->createToken();

Pri obdelavi oddaje obrazca preverite, ali je žeton veljaven:

$security = new XoopsSecurity();
if (!$security->check()) {
redirect_header('index.php', 3, _MD_TOKENEXPIRED);
exit();
}

Pri uporabi razredov obrazcev XOOPS je zaščita žetonov enostavna:

// Create a form
$form = new XoopsThemeForm('Add Item', 'form_name', 'submit.php');
// Add form elements
$form->addElement(new XoopsFormText('Title', 'title', 50, 255, ''));
$form->addElement(new XoopsFormTextArea('Content', 'content', ''));
// Add hidden token field - ALWAYS include this
$form->addElement(new XoopsFormHiddenToken());
// Add submit button
$form->addElement(new XoopsFormButton('', 'submit', _SUBMIT, 'submit'));

Za obrazce po meri HTML, ki ne uporabljajo XoopsForm:

// In your form template or PHP file
$security = new XoopsSecurity();
?>
<form method="post" action="submit.php">
<input type="text" name="title" />
<textarea name="content"></textarea>
<!-- Include the token -->
<?php echo $security->getTokenHTML(); ?>
<button type="submit">Submit</button>
</form>

Pri ustvarjanju obrazcev v predlogah Smarty:

// In your PHP file
$security = new XoopsSecurity();
$GLOBALS['xoopsTpl']->assign('token', $security->getTokenHTML());
{* In your template *}
<form method="post" action="submit.php">
<input type="text" name="title" />
<textarea name="content"></textarea>
{* Include the token *}
<{$token}>
<button type="submit">Submit</button>
</form>
// In your form processing script
$security = new XoopsSecurity();
// Verify the token
if (!$security->check()) {
redirect_header('index.php', 3, _MD_TOKENEXPIRED);
exit();
}
// Token is valid, process the form
$title = $_POST['title'];
// ... continue processing
$security = new XoopsSecurity();
if (!$security->check()) {
// Get detailed error information
$errors = $security->getErrors();
// Log the error
error_log('CSRF token validation failed: ' . implode(', ', $errors));
// Redirect with error message
redirect_header('form.php', 3, 'Security token expired. Please try again.');
exit();
}

Pri delu z zahtevami AJAX vključite žeton v zahtevo:

// JavaScript - get token from hidden field
var token = document.querySelector('input[name="XOOPS_TOKEN_REQUEST"]').value;
// Include in AJAX request
fetch('ajax_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=save&XOOPS_TOKEN_REQUEST=' + encodeURIComponent(token)
});
// PHP AJAX handler
$security = new XoopsSecurity();
if (!$security->check()) {
echo json_encode(['error' => 'Invalid security token']);
exit();
}
// Process AJAX request

Za dodatno zaščito, predvsem za zahteve AJAX, lahko preverite tudi napotitelja HTTP:

$security = new XoopsSecurity();
// Check referer header
if (!$security->checkReferer()) {
echo json_encode(['error' => 'Invalid request']);
exit();
}
// Also verify the token
if (!$security->check()) {
echo json_encode(['error' => 'Invalid token']);
exit();
}
$security = new XoopsSecurity();
// Perform both checks
if (!$security->checkReferer() || !$security->check()) {
redirect_header('index.php', 3, 'Security validation failed');
exit();
}

Žetoni imajo omejeno življenjsko dobo, da preprečijo napade ponovitve. To lahko konfigurirate v nastavitvah XOOPS ali elegantno ravnate s preteklimi žetoni:

$security = new XoopsSecurity();
if (!$security->check()) {
// Token may have expired
// Regenerate form with new token
redirect_header('form.php', 3, 'Your session has expired. Please submit the form again.');
exit();
}

Ko imate na isti strani več obrazcev, mora imeti vsak svoj žeton:

// Form 1
$form1 = new XoopsThemeForm('Form 1', 'form1', 'submit1.php');
$form1->addElement(new XoopsFormHiddenToken('token1'));
// Form 2
$form2 = new XoopsThemeForm('Form 2', 'form2', 'submit2.php');
$form2->addElement(new XoopsFormHiddenToken('token2'));

Vedno uporabljajte žetone za operacije spreminjanja stanja

Section titled “Vedno uporabljajte žetone za operacije spreminjanja stanja”

Vključite žetone v kateri koli obliki, ki:

  • Ustvari podatke
  • Posodablja podatke
  • Izbriše podatke
  • Spremeni uporabniške nastavitve
  • Izvaja morebitna upravna dejanja

Ne zanašajte se samo na preverjanje napotnikov

Section titled “Ne zanašajte se samo na preverjanje napotnikov”

Glava napotitelja HTTP je lahko:

  • Brez orodij za zasebnost
  • Manjka v nekaterih brskalnikih
  • V nekaterih primerih ponarejen

Vedno uporabljajte preverjanje žetonov kot glavno obrambo.

Razmislite o regeneraciji žetonov:

  • Po uspešni oddaji obrazca
  • Po login/logout
  • V rednih intervalih za dolge seje
$security = new XoopsSecurity();
if (!$security->check()) {
// Store form data temporarily
$_SESSION['form_backup'] = $_POST;
// Redirect back to form with message
redirect_header('form.php?restore=1', 3, 'Please resubmit the form.');
exit();
}

Težava: Varnostno preverjanje ne uspe z “žetona ni bilo mogoče najti”

Rešitev: Zagotovite, da je polje žetona vključeno v vaš obrazec:

$form->addElement(new XoopsFormHiddenToken());

Težava: uporabniki po dolgem izpolnjevanju obrazca vidijo »žeton je potekel«.

Rešitev: razmislite o uporabi JavaScripta za občasno osveževanje žetona:

// Refresh token every 10 minutes
setInterval(function() {
fetch('refresh_token.php')
.then(response => response.json())
.then(data => {
document.querySelector('input[name="XOOPS_TOKEN_REQUEST"]').value = data.token;
});
}, 600000);

Težava: AJAX zahteve ne uspejo preveriti veljavnosti žetona

Rešitev: Zagotovite, da je žeton posredovan z vsako zahtevo AJAX in jo preverite na strani strežnika:

// AJAX handler
header('Content-Type: application/json');
$security = new XoopsSecurity();
if (!$security->check(true, false)) { // Don't clear token for AJAX
http_response_code(403);
echo json_encode(['error' => 'Invalid token']);
exit();
}
form.php
<?php
require_once dirname(__DIR__) . '/mainfile.php';
$security = new XoopsSecurity();
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!$security->check()) {
redirect_header('form.php', 3, 'Security token expired. Please try again.');
exit();
}
// Process valid submission
$title = $myts->htmlSpecialChars($_POST['title']);
// ... save to database
redirect_header('success.php', 3, 'Item saved successfully!');
exit();
}
// Display form
$GLOBALS['xoopsOption']['template_main'] = 'mymodule_form.tpl';
include XOOPS_ROOT_PATH . '/header.php';
$form = new XoopsThemeForm('Add Item', 'add_item', 'form.php');
$form->addElement(new XoopsFormText('Title', 'title', 50, 255, ''));
$form->addElement(new XoopsFormTextArea('Content', 'content', ''));
$form->addElement(new XoopsFormHiddenToken());
$form->addElement(new XoopsFormButton('', 'submit', _SUBMIT, 'submit'));
$GLOBALS['xoopsTpl']->assign('form', $form->render());
include XOOPS_ROOT_PATH . '/footer.php';

#security #csrf #XOOPS #forms #tokens #XoopsSecurity