問題描述

我有一個非常具體的用例,該網站為律師建立,每個客户都可以登錄自己的’specific page/portal'(自定義帖子類型),無需訪問 wp-admin 等 (我創建了所有登錄/註冊/profile-editing 頁面前端) 。在這個頁面/門户中,律師將留下客户端下載的消息和文件,從理論上説,一個客户端可以猜測 (或者如果有其他客户端文件的知識) 其他文件名稱和下載,從而創建隱私/安全性問題/機密材料等

我正在尋找解決方案的想法/概念,我最初的想法是讓下載鏈接指向一些 download.php 發送附件 id,用户 ID,頁面/門户網站 ID 和隨機數,並在另一端處理。 。

你怎麼看?我在正確的軌道上還是這種方法有缺陷?

謝謝!

最佳解決方案

需要做的是,您需要通過 WordPress 為所需的文件類型代理下載請求。假設您要限制對”.doc” 文件的訪問。

1. 定義一個查詢變量,指示所請求的文件

function add_get_file_query_var( $vars ) {
    $vars[] = 'get_file';
    return $vars;
}
add_filter( 'query_vars', 'add_get_file_query_var' );

2. 更新.htaccess 將受限文件的請求轉發到 WordPress

這將捕獲您要限制的文件的請求,並使用上面的自定義查詢變量將其發送回 WordPress 。在 RewriteCond 線之前插入以下規則。

RewriteRule ^wp-content/uploads/(.*.docx)$ /index.php?get_file=$1

3. 在自定義查詢變量中捕獲請求的文件名; 並驗證對該文件的訪問權限:

function intercept_file_request( $wp ) {
    if( !isset( $wp->query_vars['get_file'] ) )
        return;

    global $wpdb, $current_user;

    // Find attachment entry for this file in the database:
    $query = $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE guid='%s'", $_SERVER['REQUEST_URI'] );
    $attachment_id = $wpdb->get_var( $query );

    // No attachment found. 404 error.
    if( !$attachment_id ) {
        $wp->query_vars['error'] = '404';
        return;
    }

    // Get post from database
    $file_post = get_post( $attachment_id );
    $file_path = get_attached_file( $attachment_id );

    if( !$file_post || !$file_path || !file_exists( $file_path ) ) {
        $wp->query_vars['error'] = '404';
        return;
    }

    // Logic for validating current user's access to this file...
    // Option A: check for user capability
    if( !current_user_can( 'required_capability' ) ) {
        $wp->query_vars['error'] = '404';
        return;
    }

    // Option B: check against current user
    if( $current_user->user_login == "authorized_user" ) {
        $wp->query_vars['error'] = '404';
        return;
    }

    // Everything checks out, user can see this file. Simulate headers and go:
    header( 'Content-Type: ' . $file_post->post_mime_type );
    header( 'Content-Dispositon: attachment; filename="'. basename( $file_path ) .'"' );
    header( 'Content-Length: ' . filesize( $file_path ) );

    echo file_get_contents( $file_path );
    die(0);
}
add_action( 'wp', 'intercept_file_request' );

NB 此解決方案適用於 single-site 安裝!這是因為 WordPress MU 已經通過 wp-includes/ms-files.php 在 sub-sites 中轉發上傳的文件請求。 WordPress MU 也有一個解決方案,但是它有更多的參與。

次佳解決方案

我最近有一個相關的問題和 wrote this article about it

我會假設下載是通過 WordPress 的媒體處理上傳的,否則你有一個下載的附件 ID 。

解決方案綱要

  • 製作上傳目錄’secure'(在這個意義上,我只是指使用.htaccess 阻止任何嘗試直接訪問上傳目錄 (或其 sub-directory) 中的文件 – 例如通過 mysite.com/wp-content/uploads/conf/2012/09/myconfidentialfile.pdf)

  • 創建包含附件 ID 的下載鏈接 – 這通過 WordPress 檢查用户查看附件允許/拒絕訪問權限。

Caveats

  • 這使得.htaccess 提供安全性。如果這不可用/打開 (例如,nginx 服務器),那麼你將不會有太多的安全性。您可以阻止用户瀏覽 uplods 目錄。但直接訪問將工作。

  • 按照上述。如果您需要絕對的安全性,則不應在分發中使用。如果你的具體設置是有效的 – 但一般來説,它是不能保證的。我的鏈接文章部分是為瞭解決這個問題。

  • 你會鬆開縮略圖。阻止直接訪問文件夾或 sub-folder 將意味着無法查看該文件夾中的文件的縮略圖。我的鏈接文章部分嘗試解決這個問題。

阻止直接訪問

要在您的上傳文件夾 (或子文件夾 – 所有保密材料必須位於此文件夾內的任何深度) 上執行此操作。放置一個.htaccess 文件與以下:

Order Deny,Allow
Deny from all

在下面我假設你將附加機密資料到帖子類型’client’ 。上傳到 client-edit 頁面上的任何媒體將存儲在 uploads/conf/文件夾中

設置受保護的 uploads 目錄的功能

function wpse26342_setup_uploads_dir(){

    $wp_upload_dir = wp_upload_dir();
    $protected_folder = trailingslashit($wp_upload_dir['basedir']) . 'conf';

    // Do not allow direct access to files in protected folder
    // Add rules to /uploads/conf/.htacess
    $rules = "Order Deny,Allown";
    $rules .= "Deny from all";

    if( ! @file_get_contents( trailingslashit($protected_folder).'.htaccess' ) ) {
            //Protected directory doesn't exist - create it.
        wp_mkdir_p( $protected_folder);
    }
    @file_put_contents( trailingslashit($protected_folder).'.htaccess', $rules );

     //Optional add blank index.php file to each sub-folder of protected folder.
}

上傳保密材料

   /**
    * Checks if content is being uploaded on the client edit-page
    * Calls a function to ensure the protected file has the .htaccess rules
    * Filters the upload destination to the protected file
    */
    add_action('admin_init', 'wpse26342_maybe_change_uploads_dir', 999);
    function wpse26342_maybe_change_uploads_dir() {
        global $pagenow;

        if ( ! empty( $_POST['post_id'] ) && ( 'async-upload.php' == $pagenow || 'media-upload.php' == $pagenow ) ) {
                if ( 'client' == get_post_type( $_REQUEST['post_id'] ) ) {
                       //Uploading content on the edit-client page

                       //Make sure uploads directory is protected
                       wpse26342_setup_uploads_dir();

                       //Change the destination of the uploaded file to protected directory.
                       add_filter( 'upload_dir', 'wpse26342_set_uploads_dir' );
                }
        }

    }

完成後,上傳的內容應該在 uploads/conf 內,並嘗試使用瀏覽器直接訪問它不應該。

下載內容

這很容易下載網址可以是 www.site.com?wpse26342download=5(其中 5 是上傳的內容的附件 ID) 。我們使用它來標識附件,檢查當前用户的權限並允許他們下載。

首先設置查詢變量

/**
 * Adds wpse26342download to the public query variables
 * This is used for the public download url
 */
add_action('query_vars','wpse26342_add_download_qv');
function wpse26342_add_download_qv( $qv ){
    $qv[] = 'wpse26342download';
    return $qv;
}}

現在設置一個監聽器 (可能) 觸發下載…

add_action('request','wpse26342_trigger_download');
function wpse26342_trigger_download( $query_vars ){

        //Only continue if the query variable set and user is logged in...
    if( !empty($query_vars['wpse26342download']) && is_user_logged_in() ){

        //Get attachment download path
        $attachment = (int) $query_vars['wpse26342download'];
        $file = get_attached_file($attachment);

        if( !$file )
             return;

        //Check if user has permission to download. If not abort.
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='.basename($file));
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file));

        ob_clean();
        flush();
        readfile($file);
        exit();
    }
    return $query_vars;
}

最後評論

上面的代碼可能包含錯誤/語法錯誤,並且未經測試,並且您自己承擔風險:) 。

下載網址可以使用’prettified’ 重寫。如註釋中所述,您可以在受保護文件夾的每個子節點中添加一個空白的 index.php,以防止瀏覽 – 但是這應該由.htaccess 規則阻止。

一個更安全的方法是將公共文件存儲在公共目錄之外。或者像 Amazon S3 這樣的外部服務。對於後者,您需要生成一個有效的 URL 來從 Amazon 獲取文件 (使用您的私鑰) 。這兩者都需要您的主機/第三方服務的一定程度的信任。

我會謹慎使用任何建議他們提供’protected downloads’ 的 plug-ins 。我沒有發現任何提供足夠的安全性。請不要這個解決方案的注意事項 – 我歡迎任何建議或批評。

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。