ट्रेसिंग टिल्ड्स के साथ वर्डप्रेस मैचिंग यूआरएल


11

मुझे एक भेद्यता रिपोर्ट सौंपी गई है (1) जिसका अर्थ यह लग रहा है कि निम्नलिखित टिल्डों के साथ जिस तरह से वर्डप्रेस यूआरएल को संभालता है उसमें एक सुरक्षा समस्या हो सकती है। ऐसा लगता है कि स्कैनर को लगता है कि वेबसाइट कुछ निर्देशिका लिस्टिंग और इस तरह की सेवा दे सकती है।

मुझे आश्चर्य हुआ कि मेरी वेबसाइट अभी भी उन विभिन्न URL पर सामग्री परोस रही है, इसलिए मैंने पूरी तरह से रिक्त WP उदाहरण स्थापित करके एक परीक्षण किया, "पोस्ट नाम" पर्मलिंक्स पर स्विच किया, और पुष्टि की कि हां, जोड़े गए टिल्ड वाले किसी भी URL की अभी भी व्याख्या है टिल्ड के बिना URL।

वास्तव में, इस तरह एक यूआरएल:

https://mywordpresssite.com/my-permalink

निम्नलिखित URL के साथ भी सुलभ है:

https://mywordpresssite.com/my-permalink~
https://mywordpresssite.com/my-permalink~/
https://mywordpresssite.com/my-permalink~~~~~~

मुझे यह देखने के लिए थोड़ी सी तकलीफ हुई कि WP, पर्मलिंक्स को कहाँ तक पहुँचाता है, और मैंने इसे विधि class-wp.phpमें नीचे ट्रैक किया parse_request, लेकिन इससे बहुत आगे नहीं बढ़ सका।

मेरा प्रश्न यह है कि क्या यह WP के लिए अभिप्रेत व्यवहार है, और यदि ऐसा है, तो क्या ऐसा कोई तरीका है जिससे मैं इसे बंद कर सकूं ताकि टिल्ड का मिलान न हो? WP URL के बिना URL के साथ URL की व्याख्या क्यों करेगा?

(1) हाँ, अब हम सभी ने यूके में कुछ प्रमुख हैक और डेटा लीक देखे हैं, यह उस समय फिर से है जहां "सुरक्षा" लोग सभी दिखावा करते हैं कि वे हमारे बिट डेवलपर्स को 200-पेज स्कैन रिपोर्ट सौंपकर अपना काम कर रहे हैं। गलत-सकारात्मक और सामान्य मुद्दों से भरे वे उम्मीद के बारे में कुछ भी नहीं जानते हैं यदि हम पढ़े और कहा रिपोर्ट पर कार्रवाई करते हैं, तो कुछ भी बुरा नहीं होगा।

जवाबों:


13

चलो सरल चलते हैं

अगर मैं ओपी को अच्छी तरह से समझता हूं, तो आपकी समस्या यह है कि एक टिल्ड वाले यूरल्स का मिलान किया जाता है।

अन्य सभी उत्तर इस तथ्य पर ध्यान केंद्रित करते हैं कि क्वेरी के लिए सैनिटाइजेशन क्वेरी करने से पहले कुछ वर्णों को अलग कर देता है, हालांकि किसी भी परिस्थिति में मैच न करने के लिए एक पुनर्लेखन नियम को रोकने में सक्षम होना चाहिए।

और यह करने योग्य है, बहुत आसान नहीं है, लेकिन करने योग्य है।

यह पहले स्थान पर क्यों मेल खाता है?

एक ही पुनर्लेखन नियम को पसंद करने example.com/postnameऔर example.com/postname~मिलान करने के दो कारण क्यों हैं , क्योंकि पदों के लिए WP पुनर्लेखन नियम पुन: लिखने वाले टैग का उपयोग करता है %postname%जो कि regex द्वारा प्रतिस्थापित किया जाता है ([^/]+)जब पुनर्लेखन नियम बनाए जाते हैं।

समस्या यह है कि regex ([^/]+)भी पोस्टनाम से मेल खाता है postname~और, स्वच्छता के कारण, नामांकित नाम postnameएक वैध परिणाम में समाप्त हो जाएगा ।

इसका मतलब यह है कि अगर हम रेगेक्स ([^/]+)को ([^~/]+)टिल्ड से बदलने में सक्षम हैं, तो अब मेल नहीं खाएंगे, इसलिए हम सक्रिय रूप से टिल्ड वाले यूरल्स को मैच के नाम से रोकते हैं।

चूंकि कोई नियम मैच नहीं करेगा, इसलिए url एक 404 होगा, जो कि अपेक्षित व्यवहार होना चाहिए, मुझे लगता है।

मिलान रोकें

add_rewrite_tagएक ऐसा फंक्शन है, जो अपने नाम के बावजूद, मौजूदा रीराइट टैग को अपडेट करने के लिए इस्तेमाल किया जा सकता है %postname%

इसलिए, यदि हम कोड का उपयोग करते हैं:

add_action('init', function() {
  add_rewrite_tag( '%postname%', '([^~/]+)', 'name=' );
});

हम अपने लक्ष्य तक पहुंच जाएगा और example.com/postname~होगा नहीं के लिए नियम से मेल example.com/postname

तो, हाँ, ऊपर की 3 लाइनें एकमात्र कोड है जिसकी आपको आवश्यकता होगी

हालाँकि, इससे पहले कि यह काम करता है, आपको बैकएंड पर पर्मलिंक सेटिंग्स पेज पर जाकर नियमों को फिर से लिखना होगा।

ध्यान दें कि regex ([^~/]+)एक tilde को पोस्ट नाम में कहीं भी होने से रोकता है, न केवल अनुगामी चरित्र के रूप में, बल्कि चूंकि पोस्ट नामों में वास्तव में sanitization की वजह से tilde नहीं हो सकता है, इसलिए यह समस्या नहीं होनी चाहिए।


1
+1 सादगी की तरह ;-) यह भी लगता है कि हम इसे अन्य शोर वर्णों के लिए भी समायोजित कर सकते हैं।
बीरगाइ

1
@ असीर हम सब नहीं? ;)
gmazzap

@ राहगीर हाँ, हम किसी भी चरित्र को छीनने से रोक सकते हैं sanitize_title, लेकिन चूंकि यह फ़िल्टर करने योग्य है, इसलिए हमेशा एक वैध समाधान लिखना संभव नहीं है। इसलिए मैं विशिष्ट गया।
gmazzap

1
इस उत्तर में अब तक का सबसे साफ समाधान है, और स्पष्ट रूप से उस मुद्दे की व्याख्या करता है जो हम सामना कर रहे हैं। बहुत बहुत धन्यवाद - आप को इनाम!
dKen

7

WP के लिए अभिप्रेत व्यवहार है

हाँ, के रूप में पहले से ही बताया गया है, WP_Query::get_posts()का उपयोग करता है sanitize_title_for_query()( जो का उपयोग करता हैsanitize_title() ) एक विलक्षण पद के पद नाम को साफ़ करने में।

संक्षेप में, पोस्ट नाम से गुजरने के बाद sanitize_title_for_query(), my-permalink === my-permalink~~~जैसा sanitize_title_for_query()कि अनुगामी हटा देता है ~~~। आप निम्न कार्य करके इसका परीक्षण कर सकते हैं:

echo  sanitize_title_for_query( 'my-permalink~~~' )

वहाँ किसी भी तरह से मैं इसे बंद कर सकते हैं तो tildes मिलान नहीं कर रहे हैं

यह कुछ ऐसा नहीं है जिसे आप बंद कर सकते हैं। इसमें एक फिल्टर होता sanitize_title()है sanitize_titleजिसका उपयोग आप व्यवहार को बदलने के लिए कर सकते हैं sanitize_title(), लेकिन यह लगभग हमेशा एक बहुत अच्छा विचार नहीं है। एसक्यूएल इंजेक्शन बहुत गंभीर है, इसलिए खराब सफाई के कारण दरार के माध्यम से कुछ फिसलने से आपकी साइट की अखंडता पर वास्तव में बुरा प्रभाव पड़ सकता है। "ओवर सैनिटेशन" कभी-कभी बट में दर्द हो सकता है।

मुझे यकीन नहीं है कि आप क्या कर रहे हैं, लेकिन मुझे संदेह है कि आप शायद इन अनुगामी टिल्ड के साथ 404 एकल पोस्ट करना चाहते हैं, आपके शब्दों में, "इसे बंद करें"। इस स्तर पर मेरे सोचने का एकमात्र तरीका मुख्य क्वेरी को रोकना है जब हमारे पास ये अनुगामी टिल्ड होते हैं। इसके लिए, हम posts_whereमुख्य क्वेरी के क्लॉज़ को फ़िल्टर कर सकते हैं ।

फिल्टर

नोट: मैंने केवल सामान्य एकवचन पदों पर विचार किया है, न कि स्थैतिक फ्रंट पेज या अटैचमेंट्स में, आप इसे शामिल करने के लिए फ़िल्टर का विस्तार कर सकते हैं

add_filter( 'posts_where', function ( $where, \WP_Query $q )
{
    // Only apply the filter on the main query
    if ( !$q->is_main_query() )
        return $where;

    // Only apply the filter on singular posts
    if ( !$q->is_singular() )
        return $where;

    // We are on a singular page, lets get the singular post name
    $name = sanitize_title_for_query( $q->query_vars['name'] );

    // Suppose $name is empty, like on ugly permalinks, lets bail and let WorPress handle it from here
    if ( !$name )
        return $where;

    // Get the single post URL
    $single_post_url = home_url( add_query_arg( [] ) );
    $parsed_url      = parse_url( $single_post_url );

    // Explode the url and return the page name from the path
    $exploded_pieces = explode( '/',  $parsed_url['path'] );
    $exploded_pieces = array_reverse( $exploded_pieces );

    // Loop through the pieces and return the part holding the pagename
    $raw_name = '';
    foreach ( $exploded_pieces as $piece ) {
        if ( false !== strpos( $piece, $name ) ) {
            $raw_name = $piece;

            break;
        }
    }

    // If $raw_name is empty, we have a serious stuff-up, lets bail and let WordPress handle this mess
    if ( !$raw_name )
        return $where;

    /**
     * All we need to do now is to match $name against $raw_name. If these two don't match,
     * we most probably have some extra crap in the post name/URL. We need to 404, even if the
     * the sanitized version of $raw_name would match $name. 
     */
    if ( $raw_name === $name )
        return $where;

    // $raw_name !== $name, lets halt the main query and 404
    $where .= " AND 0=1 ";

    // Remove the redirect_canonical action so we do not get redirected to the correct URL due to the 404
    remove_action( 'template_redirect', 'redirect_canonical' );

    return $where;
}, 10, 2 );

FEES नोट

जब हमारे पास URL होगा, तो उपरोक्त फ़िल्टर 404 पृष्ठ लौटाएगा https://mywordpresssite.com/my-permalink~~~~~~। हालाँकि, आप remove_action( 'template_redirect', 'redirect_canonical' );फ़िल्टर से हटाकर , क्वेरी को स्वचालित रूप से पुनर्निर्देशित कर सकते हैं https://mywordpresssite.com/my-permalinkऔर एकल पोस्ट प्रदर्शित कर सकते हैं redirect_canonical()जिसके कारण हुक किया गया है template_redirectजिससे वर्डप्रेस का पुनर्निर्देशन 404 जनरेट होता है


7

हाँ, यह अजीब लगता है कि हमारे लिए एक ही मैच होना चाहिए:

example.tld/2016/03/29/test/

और जैसे

example.tld/2016/03/29/..!!$$~~test~~!!$$../

ऐसा क्यों संभव है, लगता है कि यहWP_Query::get_posts() विधि का हिस्सा है :

if ( '' != $q['name'] ) {
    $q['name'] = sanitize_title_for_query( $q['name'] );

कहां sanitize_title_for_query()परिभाषित किया गया है:

function sanitize_title_for_query( $title ) {
        return sanitize_title( $title, '', 'query' );
}

sanitize_titleफ़िल्टर के साथ इस सख्त बनाना संभव होना चाहिए , लेकिन यह डिफ़ॉल्ट आउटपुट को ओवरराइड करने के लिए एक अच्छा विचार नहीं हो सकता है, इसके आधार पर sanitize_title_with_dashes, यहां स्वच्छता के लिए जिम्मेदार है। आपको इसे बदलने के बजाय एक टिकट बनाने पर विचार करना चाहिए, अगर इस व्यवहार के बारे में एक बार पहले से ही कोई वर्तमान नहीं है।

अपडेट करें

मुझे आश्चर्य है कि यदि हम वर्तमान मार्ग से शोर को साफ कर सकते हैं sanitize_title_for_query()और यदि आवश्यक हो तो साफ यूआरएल को पुनर्निर्देशित कर सकते हैं?

यहां एक डेमो है जिसे आप अपनी परीक्षा साइट पर खेल सकते हैं और अपनी आवश्यकताओं के अनुसार समायोजित कर सकते हैं:

/**
 * DEMO: Remove noise from url and redirect to the cleaned version if needed 
 */
add_action( 'init', function( )
{
    // Only for the front-end
    if( is_admin() )
        return;

    // Get current url
    $url = home_url( add_query_arg( [] ) );

    // Let's clean the current path with sanitize_title_for_query()
    $parse = parse_url( $url );
    $parts = explode( '/',  $parse['path'] );
    $parts = array_map( 'sanitize_title_for_query', $parts );   
    $path_clean = join( '/', $parts );
    $url_clean = home_url( $path_clean );
    if( ! empty( $parse['query'] ) )
        $url_clean .= '?' . $parse['query'];

    // Only redirect if the current url is noisy
    if( $url === $url_clean )
        return;
    wp_safe_redirect( esc_url_raw( $url_clean ) );
    exit;
} );

sanitize_title_with_dashes()फ़िल्टर से बचने और बदलने के लिए सीधे उपयोग करना बेहतर हो सकता है :

$parts = array_map( 'sanitize_title_for_query', $parts );

साथ में:

foreach( $parts as &$part )
{
    $part = sanitize_title_with_dashes( $part, '', 'query' );
}

ps: मुझे लगता है कि मैंने इस ट्रिक को सीखा add_query_arg( [] ), @gmazzap ;-) से खाली जगह के साथ वर्तमान रास्ता पाने के लिए , कोडेक्स में भी इस पर ध्यान दिया गया है। esc_url()आउटपुट का प्रदर्शन करते समय add_query_arg( [] )या esc_url_raw()जब इसे रीडायरेक्ट किया जाता है, का उपयोग करने के अनुस्मारक के लिए @gmazzap के लिए फिर से धन्यवाद । उसके लिए पिछले कोडेक्स संदर्भ को भी देखें।


+1 केवल स्पष्ट करने के लिए, उन विशेष वर्णों को हटा दिया जाता है, इसलिए, हालांकि URL का अजीब संस्करण स्थान बार में दिखाई देता है, वर्डप्रेस वास्तविक URL के साथ काम करता है, यही वजह है कि अनुरोध पहली जगह पर काम करता है। मैं उस व्यवहार के साथ किसी भी महापौर सुरक्षा जोखिम नहीं देख रहा हूं।
निकोलई

1
हां मुझे लगता है कि हमें इस @ialocin
birgire

1
यकीन है, जब तक कोई बहुत अच्छा कारण नहीं है, यह एक परेशानी है इसके लायक नहीं है। यह कहने के लिए नहीं, यह डेवलपर्स की पवित्रता के लिए सबसे अच्छा नहीं है - तकनीकी स्वच्छता में भी नहीं। बस मेरे दो सेंट हालांकि।
निकोलाई

1
@birgire जब की तरह तो इस्तेमाल किया add_query_argकी जरूरत के साथ भाग जा करने के लिए esc_urlया esc_url_rawसुरक्षा के मुद्दों को रोकने के लिए ...
gmazzap

आह हाँ धन्यवाद, अगर मुझे सही ढंग से याद है तो यह हाल ही में @gmazzap
birgire

3

मुझे वर्डप्रेस के अनुरोध के प्रसंस्करण, और तदनुसार अपने लक्ष्यों को पूरा करने के लिए वर्डप्रेस के व्यवहार को बदलने की एक विधि बताएं।

अनुरोध को पार्स करना

जब वर्डप्रेस एक अनुरोध प्राप्त करता है, तो यह अनुरोध को अलग करने और इसे एक पृष्ठ में बदलने की प्रक्रिया शुरू करता है। इस प्रक्रिया का मूल तब शुरू होता है जब वर्डप्रेस मुख्य क्वेरी विधि WP::main()कहलाती है। यह फ़ंक्शन क्वेरी को पार्स करता है, जैसा कि आपने सही तरीके से parse_request()(में includes/class-wp.php) पहचाना है । वहां, वर्डप्रेस एक फिर से लिखना नियमों के खिलाफ यूआरएल से मेल खाने की कोशिश करता है । जब URL का मिलान किया जाता है, तो यह विशेष भागों जैसे क्वेरी स्ट्रिंग को गड़बड़ाने urlencode()से रोकने के लिए, URL भागों का एक क्वेरी स्ट्रिंग बनाता है और इन हिस्सों (दो स्लैश के बीच सब कुछ) का उपयोग &करता है। ये एन्कोड किए गए वर्ण आपको यह सोचने के लिए प्रेरित कर सकते हैं कि समस्या वहां रहती थी, लेकिन क्वेरी स्ट्रिंग को पार्स करते समय वे वास्तव में उनके संबंधित "वास्तविक" वर्णों में बदल जाते हैं।

अनुरोध के साथ जुड़े क्वेरी को चलाना

WordPress द्वारा URL को पार्स करने के बाद, यह मुख्य क्वेरी क्लास सेट करता है WP_Query, जो क्लास के उसी main()तरीके से किया जाता है WP। गोमांस WP_Queryअपनी get_posts()विधि में पाया जा सकता है जहां सभी क्वेरी तर्क पार्स और sanitized हैं और वास्तविक SQL क्वेरी का निर्माण किया जाता है (और, अंततः, रन)।

इस विधि में, लाइन 2730 पर, निम्नलिखित कोड निष्पादित किया गया है:

$q['name'] = sanitize_title_for_query( $q['name'] );

यह पोस्ट टेबल से लाने के लिए पोस्ट को सैनिटाइज करता है। लूप के अंदर डिबगिंग जानकारी प्रदर्शित करने से पता चलता है कि यह वह जगह है जहां समस्या रहती है: आपका पोस्ट नाम my-permalink~, में रूपांतरित हो जाता है my-permalink, जो तब डेटाबेस से पोस्ट लाने के लिए उपयोग किया जाता है।

पद शीर्षक स्वच्छता समारोह

फ़ंक्शन उचित मापदंडों के साथ sanitize_title_for_queryकॉल करता है sanitize_title, जो शीर्षक को पवित्र करने के लिए आगे बढ़ता है। अब इस फ़ंक्शन का मूल sanitize_titleफ़िल्टर लागू कर रहा है :

$title = apply_filters( 'sanitize_title', $title, $raw_title, $context );

इस फ़िल्टर में, मूल वर्डप्रेस, इससे जुड़ा एक एकल फ़ंक्शन है sanitize_title_with_dashes:। मैंने इस फ़ंक्शन का एक व्यापक अवलोकन लिखा है, जो यहां पाया जा सकता हैइस फ़ंक्शन में, वह रेखा जो आपकी समस्या का कारण बन रही है

$title = preg_replace('/[^%a-z0-9 _-]/', '', $title);

यह रेखा अल्फ़ान्यूमेरिक वर्ण, रिक्त स्थान, हाइफ़न और अंडरस्कोर को छोड़कर सभी वर्णों को स्ट्रिप करती है।

आपकी समस्या का समाधान

इसलिए, मूल रूप से आपकी समस्या को हल करने का एक ही तरीका है: sanitize_title_with_dashesफ़ंक्शन को फ़िल्टर से निकालना और इसे अपने स्वयं के फ़ंक्शन के साथ बदलना। यह वास्तव में ऐसा करना मुश्किल नहीं है, लेकिन :

  1. जब वर्डप्रेस टाइटल को सैनिटाइज करने की आंतरिक प्रक्रिया को बदलता है, तो इससे आपकी वेबसाइट पर बड़ा प्रभाव पड़ेगा।
  2. इस फिल्टर में हुक करने वाले अन्य प्लगइन्स नई कार्यक्षमता को सही ढंग से संभाल नहीं सकते हैं।
  3. सबसे महत्वपूर्ण : वर्डप्रेस इस पंक्ति द्वारा सीधे SQL क्वेरी में sanitize_titleफ़ंक्शन के परिणाम का उपयोग करता है :

    $where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'";

    क्या आपको कभी फ़िल्टर को बदलने पर विचार करना चाहिए, सुनिश्चित करें कि आप क्वेरी में उपयोग होने से पहले शीर्षक को ठीक से छोड़ दें!

निष्कर्ष: जहां तक ​​सुरक्षा का सवाल है, आपकी समस्या को हल करना आवश्यक नहीं है, लेकिन क्या आप इसे करना चाहते हैं, sanitize_title_with_dashesअपनी कार्यक्षमता से बदलें और एसक्यूएल से बचने पर ध्यान दें।

NB सभी फ़ाइल नाम और लाइन नंबर वर्डप्रेस 4.4.2 फ़ाइलों के साथ मेल खाते हैं।


3

कुछ लोगों ने पहले ही समस्या बताई है, इसलिए मैं अभी एक वैकल्पिक समाधान पोस्ट करूँगा। सुंदर आत्म-व्याख्यात्मक होना चाहिए।

add_action( 'template_redirect', function() {
    global $wp;

    if ( ! is_singular() || empty( $wp->query_vars['name'] ) )
        return;

    if ( $wp->query_vars['name'] != get_query_var( 'name' ) ) {
        die( wp_redirect( get_permalink(), 301 ) );
        // or 404, or 403, or whatever you want.
    }
});

आप हालांकि, के बाद से श्रेणीबद्ध पोस्ट प्रकार के लिए कुछ कुछ अलग करना होगा WP_Queryचलेंगे pagenameके माध्यम से wp_basenameतो है और फिर इसे स्वच्छ, query_vars['pagename']और get_query_var('pagename')बच्चों के लिए मेल नहीं खाएगा, क्योंकि बाद के माता-पिता हिस्सा शामिल नहीं होंगे।

काश, redirect_canonicalबस इस बकवास का ख्याल रखा जाता।


0

यह FIX है ... वर्डप्रेस जेनर के बग के लिए Wordpress उत्पन्न ब्लॉक के ऊपर BEGIN सुरक्षा मॉड ब्लॉक है।

# BEGIN security mod
<IfModule mod_rewrite.c>
RewriteRule ^.*[~]+.*$ - [R=404]
</IfModule>
#END security mod

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /wordpress/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wordpress/index.php [L]
</IfModule>

# END WordPress

-3

आप हमेशा अपनी .htaccessफ़ाइल में निम्न जोड़कर देख सकते हैं:

RewriteEngine On
RewriteRule \.php~$  [forbidden,last]

ऊपर दी गई दूसरी पंक्ति सही दिखाए गए पहली पंक्ति के नीचे जानी चाहिए। इसे index.php~URL में प्रदर्शित होने से रोकना चाहिए ।


इस सुंदर permalinks के लिए काम नहीं करता है सवाल के बारे में है, है ना?
निकोलई
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.