使用自訂驗證器在Adaptive Forms中掃描檔案附件

檔案附件病毒掃描器/驗證器管道:已附加檔案,您的FileAttachmentValidator已執行,而且已接受或拒絕提交

[AEM Forms]{class="badge positive" title="套用至AEM Forms"}

檔案附件病毒掃描程式/驗證程式功能屬於早期採用者程式。 您可以使用官方電子郵件 ID 寫信至 aem-forms-ea@adobe.com,以加入早期採用者計劃並要求存取該功能。

最適化Forms可在提交時將每個上傳的附件傳遞至您選擇的驗證器。 驗證器在伺服器上執行,在記憶體中接收檔案,並決定接受或拒絕提交,因此不會持續儲存惡意或不相容的檔案。 因為您提供驗證器,所以您可以連線到任何您已經使用的防毒引擎、惡意程式碼掃描程式或自訂驗證邏輯。

本文說明此功能、記錄您實作的FileAttachmentValidator介面,並逐步說明如何建立防毒驗證器。 如需完整的引擎特定範例,請參閱隨附教學課程使用ClamAV掃描檔案附件

運作方式 how-it-works

當使用者提交已選取驗證器的調適型表單時,AEM會在處理提交之前叫用您上傳附件的驗證器:

  1. 使用者附加檔案並選取​提交
  2. 在伺服器上,AEM會呼叫您驗證器的validateFileAttachment方法,將附件(包括其原始位元組)傳遞為FileAttachmentWrapper
  3. 您的驗證程式會呼叫防毒引擎、套用驗證規則或兩者來檢查檔案,然後傳回FileAttachmentValidationResult
  4. 如果結果有效,則會繼續提交。 如果無效,AEM會封鎖提交、顯示使用者來自結果的訊息,並標示附件欄位。

此模型的兩個屬性對安全性而言很重要:

  • 伺服器端。 該檢查在伺服器上執行,因此無法從瀏覽器繞過。
  • 持續之前掃描。 在儲存檔案之前,會先從記憶體評估檔案,因此絕不會將拒絕的檔案寫入存放庫。

可用性和先決條件 prerequisites

  • 根據核心元件的最適化表單。
  • Maven專案已設定為建置和部署AEM套件組合。
  • 提供com.adobe.forms.common.service介面(FileAttachmentValidatorFileAttachmentWrapperFileAttachmentValidationResultFileAttachmentValidatorManager)的編譯階段相依性: com.adobe.forms.foundation:adobe-xfaforms-common,整合在AEM Forms附加元件SDK中。 請參閱ClamAV教學課程的步驟3,瞭解從何處取得以及如何在本機安裝。
  • 您專案中的最適化表單容器​Proxy元件 (擴充核心元件的標準模式),因此您有地方可以新增中說明的提交索引標籤欄位。將驗證器欄位新增至表單對話方塊。 這僅適用於核心元件型表單。
NOTE
檔案附件病毒掃描程式/驗證器​欄位是​ ​隨開即用。 您可在專案的「最適化表單容器」元件上,透過小型對話方塊擴充功能自行新增。 這是針對每個專案的一次性步驟(不是針對每個驗證器)。 請參閱將驗證器欄位新增至表單對話方塊

FileAttachmentValidator介面 interface-reference

您藉由實作com.adobe.forms.common.service.FileAttachmentValidator並將其註冊為OSGi服務來新增驗證器。 介面會定義兩種方法。

FileAttachmentVeritor fileattachmentvalidator

方法
傳回
說明
validateFileAttachment(FileAttachmentWrapper fileAttachmentWrapper)
FileAttachmentValidationResult
由框架針對已上傳的附件進行呼叫。 檢查附件並傳回結果,指出是否接受。
getFileAttachmentValidatorName()
String
傳回識別此驗證器的名稱。 此名稱用於選取表單上的驗證器。

FileAttachmentWrapper fileattachmentwrapper

包裝函式可讓您的程式碼存取已上傳的檔案及其中繼資料。 一般驗證器中使用的存取子包括:

方法
傳回
說明
getFileNameV2()
String
已上傳檔案的名稱,例如invoice.pdf
getContentType()
String
針對檔案報告的MIME型別,例如application/pdf
getValue()
byte[]
檔案的原始內容,儲存在記憶體中。 這是您傳遞給掃描引擎的內容。
NOTE
此表格列出驗證器中常用的存取子。 您建置的SDK版本可能會在FileAttachmentWrapper上公開其他方法。 檢查相依性中的介面以取得完整集合。

FileAttachmentValidationResult fileattachmentvalidationresult

您的驗證器傳回FileAttachmentValidationResult以告知架構是否接受附件。 使用下列引數建構它:

參數
類型
說明
isValid
boolean
true接受附件,false拒絕附件並封鎖提交。
message
String
人類看得懂的訊息。 在拒絕時,這會說明檔案未被接受的原因。
fileAttachmentWrapper
FileAttachmentWrapper
已驗證的包裝函式。

例如:new FileAttachmentValidationResult(false, "The attached file failed the security scan.", wrapper)

NOTE
如果您需要讀取FileAttachmentValidationResult回傳(例如,在測試或直接呼叫驗證器的程式碼中),請使用isFileAttachmentValid()getResponseString()/setResponseString()。 類別不會公開isValid()getMessage()方法;這些名稱會說明上述建構函式引數,而非getter。

FileAttachmentValidatormanager fileattachmentvalidatormanager

AEM註冊單一FileAttachmentValidatorManager服務,該服務位於架構與您部署的每個驗證器之間。 您通常不需要自行呼叫: AEM會使用呼叫來查詢在表單上選取的驗證器,並加以叫用。 瞭解何時進行疑難排解會很有用,因為這是提交索引標籤的下拉式清單和核心提交管道兩者的流程。

方法
傳回
說明
getValidators()
List<FileAttachmentValidator>
所有目前註冊的FileAttachmentValidator OSGi服務。
getFileAttachmentValidator(String name)
FileAttachmentValidator
getFileAttachmentValidatorName()符合name的驗證器,如果沒有符合則拋出。
validateFileAttachment(String name, List<FileAttachmentWrapper> attachments)
List<FileAttachmentValidationResult>
一次針對多個附件執行已命名的驗證器。 當提交包含一個以上的檔案時於內部使用。

註冊OSGi服務 register-service

為實作加上註解,使其在FileAttachmentValidator介面下註冊。 部署後,驗證器就可在您的表單上選取。

NOTE
本文使用現代OSGi宣告式服務註解(org.osgi.service.component.annotations)。 您可能在其他地方找到的較舊範例使用Apache Felix SCR註解(org.apache.felix.scr.annotations);這些範例已過時,不應用於新驗證程式。

建置防毒驗證器 build-validator

下列實作會顯示驗證程式的結構,而不會將其繫結至特定引擎。 以呼叫您的防毒、掃描API或驗證服務來取代scanWithYourEngine方法。

package com.example.forms.security;

import com.adobe.forms.common.service.FileAttachmentValidator;
import com.adobe.forms.common.service.FileAttachmentValidationResult;
import com.adobe.forms.common.service.FileAttachmentWrapper;
import org.osgi.service.component.annotations.Component;

@Component(service = FileAttachmentValidator.class)
public class CustomFileAttachmentValidator implements FileAttachmentValidator {

    private static final String VALIDATOR_NAME = "Custom Antivirus Scanner";

    @Override
    public FileAttachmentValidationResult validateFileAttachment(FileAttachmentWrapper wrapper) {

        if (wrapper == null) {
            return new FileAttachmentValidationResult(false, "No attachment was received.", wrapper);
        }

        byte[] content = wrapper.getValue();
        if (content == null || content.length == 0) {
            return new FileAttachmentValidationResult(false, "The attached file is empty.", wrapper);
        }

        try {
            boolean clean = scanWithYourEngine(content);
            if (clean) {
                return new FileAttachmentValidationResult(true, "File passed the security scan.", wrapper);
            }
            return new FileAttachmentValidationResult(false,
                    "The attached file failed the security scan and was rejected.", wrapper);

        } catch (Exception e) {
            // Fail closed: if the scanner cannot be reached, reject rather than let an
            // unscanned file through. See Best practices for the fail-open alternative.
            return new FileAttachmentValidationResult(false,
                    "The file could not be scanned at this time. Please try again later.", wrapper);
        }
    }

    @Override
    public String getFileAttachmentValidatorName() {
        return VALIDATOR_NAME;
    }

    /**
     * Integrate your antivirus or validation engine here.
     * Return true if the file is safe to accept, false if it should be rejected.
     */
    private boolean scanWithYourEngine(byte[] content) {
        // TODO: call a local scanning daemon (for example over a socket)
        // or a remote scanning API, and interpret its verdict.
        return true;
    }
}

建置和部署套件組合 build-deploy

編譯專案並安裝套件,以便在AEM執行個體上註冊驗證器。

在開發期間部署至本機執行個體。 從您的專案根目錄,建置並安裝套件組合至執行中的編寫執行個體:

mvn clean install -PautoInstallBundle

autoInstallBundle設定檔將編譯的套件組合推送到本機AEM執行個體(預設為http://localhost:4502)。 如果您的執行個體在不同主機、連線埠或證明資料上執行,請將它們傳遞至組建,例如:

mvn clean install -PautoInstallBundle -Daem.host=localhost -Daem.port=4502 -Dvault.user=admin -Dvault.password=admin

部署至更高的環境。 對於測試和生產,請勿手動安裝套件。 透過CI/CD管道將其部署為專案的all內容套件的一部分。 如需完整程式,請參閱部署至AEM as a Cloud Service

確認服務已註冊。 開啟元件主控台並搜尋您的驗證器類別:

http://localhost:4502/system/console/components

元件應列示其狀態,顯示為​active (或​satistified),已在FileAttachmentValidator服務下註冊。 如果不滿意,請參閱確認您的驗證程式載入並執行中

將自訂驗證器及其資料來源Servlet顯示為使用中的元件主控台

將驗證器欄位新增至表單對話方塊 add-dialog-field

本節適用於以​ 核心元件 ​為基礎的最適化Forms。 檔案附件病毒掃描程式/驗證器​欄位不在現成的最適化表單容器對話方塊中。 您可在自己的專案中將其新增一次,作為小型擴充功能。 您之後部署的每個驗證器(請參閱建置防毒驗證器)接著會自動顯示為選項;請勿對每個驗證器重複此步驟。

您專案的最適化表單容器是​Proxy元件/apps下使用sling:resourceSuperType指向真實核心元件的元件,例如:

<!-- /apps/<project>/components/adaptiveForm/formcontainer/.content.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="cq:Component"
    jcr:title="Form Container"
    sling:resourceSuperType="core/fd/components/form/container/v2/container"
    xmlns:sling="http://sling.apache.org/jcr/sling/1.0"/>

由於sling:resourceSuperType,您可以新增​ 一個新欄位 ​至繼承的[提交]索引標籤,而不複製整個對話方塊。 Sling Resource Merger只需要重新建立一直到插入點的節點名稱路徑。 請參閱一般機制的延伸元件對話方塊。 真正的OOTB提交索引標籤會將其欄位保留在content/items/tabs/items/submitActions/items/columns/items/下,所以這是映象的路徑:

<!-- /apps/<project>/components/adaptiveForm/formcontainer/_cq_dialog/.content.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
    jcr:primaryType="nt:unstructured">
  <content jcr:primaryType="nt:unstructured">
    <items jcr:primaryType="nt:unstructured">
      <tabs jcr:primaryType="nt:unstructured">
        <items jcr:primaryType="nt:unstructured">
          <submitActions jcr:primaryType="nt:unstructured">
            <items jcr:primaryType="nt:unstructured">
              <columns jcr:primaryType="nt:unstructured">
                <items jcr:primaryType="nt:unstructured">
                  <fileAttachmentValidator
                      jcr:primaryType="nt:unstructured"
                      sling:resourceType="granite/ui/components/coral/foundation/form/select"
                      fieldLabel="File Attachment Virus Scanner/Validator"
                      fieldDescription="Select a registered validator configuration to scan submitted file attachments. Select None to disable validation for this form."
                      emptyText="None"
                      name="./fileAttachmentValidator">
                    <datasource
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="<project>/datasources/fileattachmentvalidators"/>
                  </fileAttachmentValidator>
                </items>
              </columns>
            </items>
          </submitActions>
        </items>
      </tabs>
    </items>
  </content>
</jcr:root>

值得一提的兩個細節:

  • emptyText="None"​會為欄位提供未選取的預設狀態,因此未選取任何內容的表單不會套用驗證器。 您不需要將虛假「無」專案新增至下列資料來源。
  • 需要多個組態。 您可能會註冊多個驗證器,例如每個防毒引擎註冊一個,或是同一引擎中多個不同設定的執行個體。 每個已註冊的FileAttachmentValidator都有自己的getFileAttachmentValidatorName(),因此每個對話方塊都會自動顯示為個別的選項;此對話方塊片段的相關資訊不會隨您註冊的次數而改變。

datasource子節點指向您也編寫的小型Sling servlet。 它有一個工作:向FileAttachmentValidatorManager詢問getValidators(),並將每個驗證器的getFileAttachmentValidatorName()轉換為下拉式選項。 如需完整、準備就緒的實作,請參閱ClamAV教學課程的步驟7:不論您使用哪個驗證器引擎,servlet都相同,因此您可以依原樣將其複製到專案中。

將這兩個檔案部署為您專案的ui.apps內容套件和core套件組合的一部分(請參閱建置並部署套件組合)。 部署後,此對話方塊擴充功能已驗證運作正常:欄位會與現有OOTB欄位一起顯示在「提交」標籤上(而非取代它們),且將其設定為會儲存引導容器節點上的純fileAttachmentValidator屬性,AEM提交管道會透過FileAttachmentValidatorManager.getFileAttachmentValidator(name)讀取該屬性。

在您的表單上選取驗證器 select-validator

  1. 開啟最適化表單進行編輯,並選取​ 指南容器 ​以開啟​ 最適化表單容器 ​屬性。
  2. 移至​ 提交 ​標籤。
  3. 從​ File Attachment Virus Scanner / Validator ​下拉式清單中,選取您的驗證器。 假設您已完成將驗證器欄位新增至表單對話方塊,此清單會填入getFileAttachmentValidatorName()針對目前註冊的每個驗證器傳回的名稱。 選取​ (預設值)以停用此表單的驗證。
  4. 選取​ 完成 ​並儲存表單。

最適化表單容器對話方塊的提交索引標籤,其中在檔案附件病毒掃描器/驗證器欄位中選取了驗證器

IMPORTANT
如果您在[提交]索引標籤上完全看不到​ 檔案附件病毒掃描程式/驗證器 ​欄位,則您(或您的專案)尚未完成將驗證器欄位新增至表單對話方塊。 對於以核心元件為基礎的表單,此欄位絕不會現成顯示。

執行階段行為和使用者體驗 runtime-behavior

  • 檔案已接受。 當驗證器傳回有效結果時,系統就會照常執行提交作業。
  • 檔案已拒絕。 當您的驗證器傳回無效的結果時,AEM會停止提交、顯示來自結果的訊息給使用者,並在檔案附件欄位中標示驗證錯誤。 表單資料未提交。

驗證您的驗證器是否載入並執行 verify

  1. 部署後,請確認組合為作用中且元件在FileAttachmentValidator服務下方所列的OSGi主控台(Status > 元件)中符合要求。
  2. 開啟表單的​ 提交 ​設定,並確認您的驗證器出現在下拉式清單中。
  3. 使用測試檔案提交表單,並確認已叫用您的驗證器(在開發期間新增記錄陳述式)。

如果​ File Attachment Virus Scanner / Validator ​欄位本身未出現在[提交]索引標籤上:

如果欄位出現,但您的驗證器未列在下拉式清單中:

  • 確認組合已安裝且作用中,且元件已在FileAttachmentValidator下註冊,且未處於未滿足的狀態。
  • 確認getFileAttachmentValidatorName()傳回非空白的唯一名稱。
  • 部署套件組合後重新載入表單編輯器。

最佳實務和考量事項 best-practices

決定掃描的位置。 您的驗證器可呼叫在本機(或與AEM同置)或遠端掃描API執行的掃描引擎。 本機或異地引擎可在您的環境中保留檔案內容,協助滿足資料駐留及法規遵循需求。 遠端API會將檔案位元組傳送至環境外,因此請先確認資料的可接受性,然後再進行選擇。

刻意選擇失敗模式。 當掃描引擎無法連線或發生錯誤時,您可以關閉失敗(如上述範例所示,拒絕檔案)或開啟失敗(接受)。 對於安全性敏感型表單而言,「關閉失敗」是較安全的預設值。 失敗開放偏好的可用性。 選擇明確而非意外。

考慮延遲。 掃描會在提交期間同步進行,因此掃描時間會新增至使用者的提交體驗。 如果您依賴外部服務,請設定致電引擎的合理逾時,並以服務等級協定來設定期望值。

已繫結承載。 getValue()會以記憶體中byte[]的形式傳回檔案,因此大型上傳會消耗棧積。 使用檔案附件元件的檔案大小上限和支援的檔案型別來限制來源上的上傳,因此驗證器只會處理大小合理、預期的檔案。

將控制項分層。 驗證器是數層中最強的一層。 限制檔案附件元件上的檔案型別和大小、使用驗證器掃描提交內容,以及新增機器人保護(例如CAPTCHA)。 沒有單一圖層本身就足夠了。

寫入清除拒絕訊息。 結果中的message會向使用者顯示,因此使其可操作,例如「不允許此檔案型別」。 上傳PDF。」 如果您的表單提供多種語言,請考慮本地化。

安全並監視掃描通道。 使用安全傳輸至您的掃描引擎,由於它位於提交路徑中,因此保持高可用性,並記錄掃描結果以進行稽核和疑難排解。

常見問題 faq

什麼是AEM Forms中的檔案附件驗證器?
這是伺服器端服務,您在AEM中註冊,可在提交時檢查透過Adaptive Form上傳的每個檔案,並告知AEM是否接受或拒絕檔案。您透過​ 檔案附件病毒掃描程式/驗證器 ​設定在表單上選取它。

AEM何時呼叫驗證器?
在提交時,在保留表單資料和附件之前。AEM會使用附件呼叫您的validateFileAttachment方法,並在結果無效時封鎖提交。

一旦附加檔案,驗證執行時間是否可早於提交時間?
可以,作為單獨的機制。在使用者提交之前,使用最適化Forms規則編輯器中的​ 叫用服務 ​作業來呼叫檔案欄位變更事件的掃描服務。這與本文所述的FileAttachmentValidator介面無關。它會改為呼叫表單資料模型(FDM)服務。請參閱規則編輯器中的啟動服務增強功能

驗證程式是在瀏覽器中還是在伺服器上執行?
在伺服器上。無法藉由停用JavaScript或在瀏覽器中編輯頁面來略過檢查。

我可以使用此介面的任何防毒軟體嗎?
是。介面不依賴任何特定引擎。您的實作可以呼叫本機掃描精靈、商業防毒或資料遺失產品,或遠端掃描API,然後將結果對應至FileAttachmentValidationResult

被拒絕的檔案是否儲存在AEM?
否。因為在保留檔案之前,會先從記憶體評估檔案,因此絕不會將拒絕的檔案寫入存放庫。

當檔案被拒絕時,該如何顯示自訂訊息?
在您建構FileAttachmentValidationResult時設定message值。AEM在拒絕檔案時向使用者顯示該訊息。

範例情境 example-scenarios

  • 案例:​每個檔案都已被拒絕,包括乾淨的檔案。
    動作:​檢查掃描引擎或您的驗證器呼叫的相依性是否可連線。 失敗關閉的驗證器會在無法連線時拒絕所有內容,因此請先確認連線,然後檢查驗證器的記錄是否有連線錯誤。

  • 案例:​檔案附件病毒掃描程式/驗證程式欄位完全未出現在提交索引標籤上。
    動作:​確認您的專案已部署來自的對話方塊擴充功能與資料來源Servlet將驗證器欄位新增至表單對話方塊,而且您的程式已啟用任何功能切換閘道基礎管理員功能。

  • 案例:​欄位會出現,但您的驗證器並未列在下拉式清單中。
    動作:​確認組合為作用中並在FileAttachmentValidator下註冊(不是處於不滿足的狀態),getFileAttachmentValidatorName()會傳回非空白的唯一名稱,並在部署後重新載入表單編輯器。

  • 案例:​新增驗證器後,表單提交速度明顯變慢。
    動作:​掃描在提交期間同步執行,因此掃描時間會新增至使用者的提交體驗。 檢查掃描引擎的延遲,並設定合理的逾時。 請參閱延遲的帳戶

  • 案例:​您需要支援一個以上的防毒引擎,或數個相同引擎的不同設定執行個體。
    動作:​將每個動作註冊為自己的FileAttachmentValidator實作。 每個已註冊的驗證器都會透過其自己的getFileAttachmentValidatorName(),自動顯示在「提交」標籤下拉式清單中,因此無需變更任何關於對話方塊延伸模組的內容。

  • 案例:​您想要在使用者提交之前執行驗證,而不只是在提交時執行。
    動作:​請參閱驗證是否可在提交之前執行? 以上。 在規則編輯器中使用叫用服務作業,而非或與此驗證器搭配使用。

recommendation-more-help
experience-manager-cloud-service-help-main-toc