Μετάβαση στο περιεχόμενο

CSRF Προστασία

2.5.x ✅ 4.0.x ✅

Οι επιθέσεις πλαστογράφησης αιτημάτων μεταξύ ιστότοπων (CSRF) εξαπατούν τους χρήστες να εκτελέσουν ανεπιθύμητες ενέργειες σε έναν ιστότοπο όπου έχουν γίνει έλεγχος ταυτότητας. Το XOOPS παρέχει ενσωματωμένη προστασία CSRF μέσω της κατηγορίας XoopsSecurity.

  • Security-Best-Practices - Περιεκτικός οδηγός ασφαλείας
  • Input-Sanitization - MyTextSanitizer και επικύρωση
  • SQL-Injection-Prevention - Πρακτικές ασφαλείας βάσης δεδομένων

Μια επίθεση CSRF συμβαίνει όταν:

  1. Έγινε έλεγχος ταυτότητας χρήστη στον ιστότοπό σας XOOPS
  2. Ο χρήστης επισκέπτεται έναν κακόβουλο ιστότοπο
  3. Ο κακόβουλος ιστότοπος υποβάλλει ένα αίτημα στον ιστότοπό σας XOOPS χρησιμοποιώντας τη συνεδρία του χρήστη
  4. Ο ιστότοπός σας επεξεργάζεται το αίτημα σαν να προήλθε από τον νόμιμο χρήστη

Το XOOPS παρέχει την κλάση XoopsSecurity για προστασία από επιθέσεις CSRF. Αυτή η κλάση διαχειρίζεται διακριτικά ασφαλείας που πρέπει να περιλαμβάνονται σε φόρμες και να επαληθεύονται κατά την επεξεργασία αιτημάτων.

Η κλάση ασφαλείας δημιουργεί μοναδικά διακριτικά που αποθηκεύονται στη συνεδρία του χρήστη και πρέπει να περιλαμβάνονται σε φόρμες:

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

Κατά την επεξεργασία των υποβολών φόρμας, βεβαιωθείτε ότι το διακριτικό είναι έγκυρο:

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

Όταν χρησιμοποιείτε κλάσεις φόρμας XOOPS, η προστασία διακριτικών είναι απλή:

// 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'));

Για προσαρμοσμένες φόρμες HTML που δεν χρησιμοποιούν 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>

Κατά τη δημιουργία φορμών σε πρότυπα 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();
}

Όταν εργάζεστε με αιτήματα AJAX, συμπεριλάβετε το διακριτικό στο αίτημά σας:

// 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

Για πρόσθετη προστασία, ειδικά για αιτήματα AJAX, μπορείτε επίσης να ελέγξετε την παραπομπή 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();
}

Τα διακριτικά έχουν περιορισμένη διάρκεια ζωής για την αποτροπή επιθέσεων επανάληψης. Μπορείτε να το διαμορφώσετε στις ρυθμίσεις XOOPS ή να χειριστείτε με χάρη τα ληγμένα διακριτικά:

$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();
}

Όταν έχετε πολλές φόρμες στην ίδια σελίδα, η καθεμία πρέπει να έχει το δικό της διακριτικό:

// 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'));

# Να χρησιμοποιείτε πάντα διακριτικά για λειτουργίες που αλλάζουν κατάσταση

Ενότητα με τίτλο «# Να χρησιμοποιείτε πάντα διακριτικά για λειτουργίες που αλλάζουν κατάσταση»

Συμπεριλάβετε διακριτικά σε οποιαδήποτε μορφή:

  • Δημιουργεί δεδομένα
  • Ενημερώνει δεδομένα
  • Διαγράφει δεδομένα
  • Αλλάζει τις ρυθμίσεις χρήστη
  • Εκτελεί κάθε διοικητική ενέργεια

# Μην βασίζεστε αποκλειστικά στον έλεγχο παραπομπών

Ενότητα με τίτλο «# Μην βασίζεστε αποκλειστικά στον έλεγχο παραπομπών»

Η κεφαλίδα αναφοράς HTTP μπορεί να είναι:

  • Απογυμνωμένο από εργαλεία απορρήτου
  • Λείπει σε ορισμένα προγράμματα περιήγησης
  • Παραπλανήθηκε σε ορισμένες περιπτώσεις

Χρησιμοποιείτε πάντα την επαλήθευση διακριτικών ως κύρια άμυνά σας.

Εξετάστε το ενδεχόμενο αναγέννησης διακριτικών:

  • Μετά την επιτυχή υποβολή της φόρμας
  • Μετά το login/logout
  • Σε τακτά χρονικά διαστήματα για μεγάλες συνεδρίες

# Χειριστείτε τη λήξη του διακριτικού με χάρη

Ενότητα με τίτλο «# Χειριστείτε τη λήξη του διακριτικού με χάρη»
$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();
}

Πρόβλημα: Ο έλεγχος ασφαλείας αποτυγχάνει με το “token not found”

Λύση: Βεβαιωθείτε ότι το πεδίο διακριτικού περιλαμβάνεται στη φόρμα σας:

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

Πρόβλημα: Οι χρήστες βλέπουν ότι το “token έληξε” μετά τη μακροχρόνια συμπλήρωση της φόρμας

Λύση: Εξετάστε το ενδεχόμενο να χρησιμοποιήσετε JavaScript για να ανανεώνετε περιοδικά το διακριτικό:

// 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);

Πρόβλημα: AJAX αποτυχία αιτημάτων επικύρωσης διακριτικού

Λύση: Βεβαιωθείτε ότι το διακριτικό μεταβιβάζεται με κάθε αίτημα AJAX και επαληθεύστε το από την πλευρά του διακομιστή:

// 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';