WordPress REST API végpontok biztonságos jogosultságkezelése.

Nem csak a látvány számít: Biztonságos WordPress REST API végpontok készítése

Az ötleted ragyogó: a saját, egyedi admin felületedet vagy mobil appodat akarod a WordPress adatbázisodhoz kapcsolni egy REST API-n keresztül. Megvan a kreativitás, de egy kritikus kérdés merül fel: Hogyan zárjuk le az ajtót, hogy ne jöhessen be aki nem hívott? A WordPress REST API alapból erős, de saját végpontok készítésekor a biztonság teljes mértékben a mi felelősségünk. Ma ezt a láthatatlan, de létfontosságú réteget nézzük meg együtt.

Miért nem elég a sima „Hello World” végpont?

Amikor elkezdünk API végpontot készíteni, a legtöbb tutorial a minimális példával indul: regisztrálj egy route-ot, köss hozzá egy függvényt, és küldj vissza valami JSON-t. Ilyen egyszerűen meg is van a sebezhetőség.

// FIGYELMEZTETÉS: EZ BIZTONSÁGI RÉS!
add_action('rest_api_init', function () {
    register_rest_route('sajat/v1', '/adat', [
        'methods' => 'GET',
        'callback' => function() {
            return ['titkos_adat' => 'Ez bárki számára látható!'];
        },
    ]);
});

Ez a kód mindenki számára elérhetővé teszi az adatot – bejelentkezett felhasználó, vendég, vagy akár egy rosszindulatú script számára egy másik domainről. A gyakorlatban ez olyan, mintha a bankszámlakivonatodat a bejárati ajtó elé tennéd.

Az első védőfal: A jogosultságkezelő callback

A WordPress megoldása elegáns: minden route regisztrálásakor megadhatunk egy permission_callback függvényt. Ez a kapuőr, aki dönti el, hogy a kérés továbbhaladhat-e.

add_action('rest_api_init', function () {
    register_rest_route('sajat/v1', '/profil', [
        'methods' => 'GET',
        'callback' => 'sajat_api_lekeres',
        'permission_callback' => function () {
            return is_user_logged_in(); // Csak bejelentkezett felhasználók
        }
    ]);
    
    register_rest_route('sajat/v1', '/beallitasok', [
        'methods' => 'POST',
        'callback' => 'sajat_api_frissites',
        'permission_callback' => function () {
            return current_user_can('manage_options'); // Csak adminisztrátorok
        }
    ]);
});

function sajat_api_lekeres() {
    $current_user = wp_get_current_user();
    return [
        'nev' => $current_user->display_name,
        'email' => $current_user->user_email
    ];
}

A permission_callback mindig egy függvényt vagy anonym függvényt vár, ami true vagy false értéket ad vissza. Itt használhatjuk a WordPress beépített funkcióit (current_user_can, is_user_logged_in), de akár saját, komplex logikát is implementálhatunk.

Gyakori buktatók, amikbe én is belebotlottam

1. A hiányzó permission_callback: A legnagyobb hiba, ha egyáltalán nem adunk meg ilyet. A WordPress 5.5 óta a REST API kikényszeríti, hogy legyen permission_callback. Ha hiányzik, a fejlesztői konzolban figyelmeztetést kapsz, és gyakran a végpontod egyáltalán nem fog működni.

2. Túl komplex logika a callbackben: A permission_callback célja a hozzáférés eldöntése, ne a teljes üzleti logikát pakoljuk bele. Ha bonyolult ellenőrzéseket végzünk (pl. külső API hívás), az lassítja az összes kérést.

3. Nonce tokenek elfelejtése: A wp_create_nonce() és wp_verify_nonce() páros nem csak formumegjelenítésekhez kell. Ha olyan műveletet végzünk, ami állapotot módosít (POST, PUT, DELETE), a nonce tokenek létfontosságúak a CSRF támadások kivédésére. Különösen fontosak, ha a frontend jQuery-vel készül.

Egy komplett példa: Admin beállítások biztonságos mentése

Képzeljük el, hogy van egy egyedi admin panelünk, ahol csak „editor” szerepkörű felhasználók módosíthatnak beállításokat. Így nézhet ki a backend rész:

add_action('rest_api_init', function () {
    register_rest_route('portfolio/v1', '/social', [
        'methods' => 'POST',
        'callback' => 'mentes_social_links',
        'permission_callback' => 'ellenoriz_social_mentes_jogot'
    ]);
});

function ellenoriz_social_mentes_jogot($request) {
    // 1. Alap: legyen bejelentkezett
    if (!is_user_logged_in()) {
        return false;
    }
    
    // 2. Legyen editor vagy annál magasabb jogosultság
    if (!current_user_can('edit_pages')) {
        return false;
    }
    
    // 3. Ellenőrizzük a nonce-t (a frontendről kell jönnie)
    $nonce = $request->get_header('X-WP-Nonce');
    if (!wp_verify_nonce($nonce, 'wp_rest')) {
        return false;
    }
    
    return true;
}

function mentes_social_links($request) {
    $parameters = $request->get_json_params();
    
    // Input tisztítása - soha ne bízzunk a felhasználói adatokban
    $facebook = sanitize_text_field($parameters['facebook_url'] ?? '');
    $twitter = esc_url_raw($parameters['twitter_url'] ?? '');
    
    update_option('portfolio_social_facebook', $facebook);
    update_option('portfolio_social_twitter', $twitter);
    
    return [
        'success' => true,
        'message' => 'Beállítások frissítve'
    ];
}

És a frontend oldal (egy egyszerű admin panel része), ahol Bootstrap segítségével készült a felület, és jQuery kezeli a kérést:

<div class="container mt-4">
    <div class="card">
        <div class="card-header">
            <h5>Közösségi média linkek</h5>
        </div>
        <div class="card-body">
            <div class="mb-3">
                <label class="form-label">Facebook URL</label>
                <input type="text" class="form-control" id="facebook-url">
            </div>
            <div class="mb-3">
                <label class="form-label">Twitter URL</label>
                <input type="text" class="form-control" id="twitter-url">
            </div>
            <button id="mentes-gomb" class="btn btn-primary">Mentés</button>
            <div id="uzenet" class="mt-3"></div>
        </div>
    </div>
</div>

<style>
/* SCSS alapú stílus – jobb strukturáltság érdekében */
.card {
    border-radius: 10px;
    box-shadow: 0 4px 6px rgba(0,0,0,0.1);
    
    &-header {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border-radius: 10px 10px 0 0 !important;
    }
}
</style>

<script>
jQuery(document).ready(function($) {
    $('#mentes-gomb').on('click', function() {
        let gomb = $(this);
        gomb.prop('disabled', true).text('Mentés...');
        
        $.ajax({
            url: '/wp-json/portfolio/v1/social',
            method: 'POST',
            beforeSend: function(xhr) {
                // A nonce-t a wp_localize_script-ből is kaphatnánk
                xhr.setRequestHeader('X-WP-Nonce', wpApiSettings.nonce);
            },
            contentType: 'application/json',
            data: JSON.stringify({
                facebook_url: $('#facebook-url').val(),
                twitter_url: $('#twitter-url').val()
            }),
            success: function(valasz) {
                $('#uzenet').html(
                    '<div class="alert alert-success">' + valasz.message + '</div>'
                );
            },
            error: function() {
                $('#uzenet').html(
                    '<div class="alert alert-danger">Hiba történt a mentés során!</div>'
                );
            },
            complete: function() {
                gomb.prop('disabled', false).text('Mentés');
            }
        });
    });
});
</script>

A végső összegzés: A biztonság mentalitás kérdése

A biztonságos REST API végpontok nem egy egyszeri beállítás, hanem egy mentalitás. Mindig tedd fel a kérdést: „Ki számára akarom elérhetővé tenni ezt az adatot/műveletet?” A válasz alapján válaszd ki a megfelelő szűrőket:

Nyilvános adatok: permission_callback: '__return_true'Bejelentkezett felhasználók: is_user_logged_in() ellenőrzés – Specifikus jogosultság: current_user_can('capability')Egyedi logika: Saját callback a régebbi WordPress verziók kompatibilitásához

Ne feledd: a WordPress adatbázisodban a vállalkozásod szíve ver. A REST API egy hatalmas kapu, ami csodálatos lehetőségeket nyit meg – de pontosan ezért kell őrizni, mint a legfontosabb kincsedet. Szép kódolást és nyugodt éjszakákat (mert tudod, hogy az API-d védett)!