[精讚] [會員登入]
272

【Wicket】[nonce]如何導入css以及javascript

如果只是用一般的 HTML link 或是 script 標籤來寫,會被 CSP 擋住,禁止加載資源,那我們除了關閉 CSP 以外還有沒有辦法來解決呢?

分享此文連結 //n.sfs.tw/15705

分享連結 【Wicket】[nonce]如何導入css以及javascript@小編過路君子
(文章歡迎轉載,務必尊重版權註明連結來源)
2022-05-20 16:41:16 最後編修
2022-03-25 08:24:42 By 過路君子
 

哈囉大家好,這裡是找到好方法的小編過路君子

看大家都只說用 CssHeaderItem.forReference() 但是小編一直在想......所以那些人的 CSS 檔案到底放在哪裡?

 

 

如果各位有到 Stackoverflow 之類的網站先去找資料的話,應該不難發現很多人都叫我們這樣寫:

import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.request.resource.CssResourceReference;

@Override
public void renderHead(IHeaderResponse response)
{
    response.render(CssHeaderItem.forReference(new CssResourceReference(myCssFile.class, "myCssFile.css")));
}

那現在問題來了,這幾行要寫在哪裡?css 檔案要放在哪裡?需要掛載 css 檔案嗎?

 

先說結論,小編在一陣摸索之後看了以下的訊息:

(所有圖片點擊都可以放大、變高清)

那小編看了以下的輸出至少得知了好像要把 css 打包成 package,但是真的有夠麻煩的

 

所以我們今天不會使用這個方式。

我們直接使用網址的方式,換言之,就是只要寫網址進去就可以了,不用管這個 css 或是 javascript 是同源還是外部的,只要有網址就可以了。

如果真的有需要使用第三方的資源檔,那還是使用小編等等介紹的方式,就算該程式碼帶有惡意,我們最少還是有機會擋下來的。

有關 XSS 的更多資訊可以參考這篇他人的文章:前端防禦從入門到棄坑——CSP變遷@程序猿哪些事

那如果今天我們真的需要從其他網站獲取資訊(例如:溫度、濕度)怎麼辦?也很簡單,就是去設定一下 CSP 的 connect-src 即可,如何設定可以參考這小編這篇文章:【Wicket】[CSP] Content-Security-Policy & Content-Security-Policy-Report-Only@小編過路君子

 

那我們在開始前,照慣例小編一樣先附上目錄結構:

小編會將 css 和 js 放在 webapp 下,而不是 java 下的原因是:

放在 webapp 下走的是 web.xml 的設定,網址就是路徑;但若放在 java 下走的就是 webRoute.java 的設定,網址預設又臭又長,若要漂亮的網址就要掛載,那既然掛載了,不就跟我們直接放在 webapp 一樣?

 

 

如何加載 CSS

因為 CSS 相對起來比較單純,所以我們從這邊開始。

那以我們今天要在 index.html 新增 index.css 為例,假設今天 index.css 內有以下內容:

接著,我們打開 index.java 添加以下的程式碼:

import org.apache.wicket.request.Url;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.CssReferenceHeaderItem;

public class index extends WebPage
{
    @Override
    public void renderHead(IHeaderResponse response)
    {
        /* 取得目前網頁網址 */
        Url url = RequestCycle.get().getRequest().getUrl();
        String fullUrl = RequestCycle.get().getUrlRenderer().renderFullUrl(url);

        String rootUrl;
        try {rootUrl = fullUrl.substring(0, fullUrl.indexOf('/', fullUrl.indexOf('/')+2));}
        catch(Exception error) {rootUrl = fullUrl;}

        /* 渲染CSS */
        response.render(CssReferenceHeaderItem.forUrl(rootUrl + "/css/index.css"));
    }
}

那其中因為小編都是使用 Wildfly 所以之前網址可能只會打 /css/index.css 這樣,但沒想到在 Apache 上面踢到大鐵板,Apache 的相對連結算法跟 Wildfly 不一樣啊!

所以現在小編不管如何都一定使用網址進行連結,這樣就沒有這個問題了;如果有興趣了解更多可以參考這篇文章:【Wicket】[URI]使用Java取得目前網址@小編過路君子

那這邊有一點要注意的是,我們不用在 HTML 裡面添加 <link href="..." />,Wicket 會自動幫我們產生,所以我們的 HTML 維持原本的樣子即可。

接著刷新頁面。

我們的 CSS 漂亮的出現了!而且還帶有 nonce,所以不會被 CSP 攔下。

 

那如果我們今天要加載的是來自其他網站的 css 呢?那剛好,小編到精讚上隨便抓了一個 css 檔來測試(原檔在這:flags.css)。

一樣的程式碼,如法炮製。

import org.apache.wicket.request.Url;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.CssReferenceHeaderItem;

public class index extends WebPage
{
    @Override
    public void renderHead(IHeaderResponse response)
    {
        /* 取得目前網頁網址 */
        Url url = RequestCycle.get().getRequest().getUrl();
        String fullUrl = RequestCycle.get().getUrlRenderer().renderFullUrl(url);

        String rootUrl;
        try {rootUrl = fullUrl.substring(0, fullUrl.indexOf('/', fullUrl.indexOf('/')+2));}
        catch(Exception error) {rootUrl = fullUrl;}

        /* 渲染第三方CSS */
        response.render(CssReferenceHeaderItem.forUrl("https://n.sfs.tw/web/css/flags.css"));
    }
}

重新載入網頁並套用對方 css 的屬性。

不要問小編為什麼控制台和網頁原始碼的 HTML 不一樣,因為小編截圖之後才想到要設一個屬性來測試,所以就臨時用 javascript 添加上去。

總之,我們的資源成功載入,屬性也成功套用,完全沒受到半點 CSP 的攔截。

對了,如果對方的 css 內有網址,例如 background: url("..."),那網址的部分照樣會被攔截,所以最好的辦法就是將所有相依資源移到我們本機,因為預設圖片等等是同源 ok 的。

 

 

如何加載 Javascript

如果只是要添加沒有對外互動的 javascript 的話相當單純,絕對不會被 CSP 攔截。

可是一旦發出網頁請求,就會看對方是什麼類型的資源,然後比對該項 CSP,如果是不被允許的,那照樣會直接禁止傳輸。

那我們一樣要在 index.html 裡面加載 index.js 檔案,假設 index.js 內有以下的程式碼:

打開 index.java 添加以下程式碼:

import org.apache.wicket.request.Url;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;

public class index extends WebPage
{
    @Override
    public void renderHead(IHeaderResponse response)
    {
        /* 取得目前網頁網址 */
        Url url = RequestCycle.get().getRequest().getUrl();
        String fullUrl = RequestCycle.get().getUrlRenderer().renderFullUrl(url);
        String rootUrl = fullUrl.substring(0, fullUrl.indexOf('/', fullUrl.indexOf('/')+2));

        /* 渲染javascript */
        response.render(JavaScriptReferenceHeaderItem.forUrl(rootUrl + "/css/index.js"));
    }
}

接著同樣刷新網頁頁面。

跟上面的 CSS 一樣,我們使用網址漂亮的渲染出了 javascript,一樣如果對 Wicket 使用 java 擷取網址有興趣的人這邊請:【Wicket】[URI]使用Java取得目前網址@小編過路君子

小編沒在精讚上面找到比較適合拿來做示範的第三方 javascript,所以示範的部分跳過,但大體邏輯跟 css 一樣:

/* 渲染第三方 javascript */
response.render(JavaScriptReferenceHeaderItem.forUrl("http://uri.here"));

那跟 css 一樣,javascript 如果會像其他的網站發出資源請求,會看請求的資源類型,然後對照相對應的 CSP,若是不符合規則則同樣會禁止存取。

所以如果需要請求其他資源的話,要嘛下載回來放本機,要嘛去修改 CSP 規則,同意下載。

如果是 css 和 javascript 那就算是同源照樣禁止傳輸,最好的辦法是像上面那樣在一開始就渲染好並放到 head 裡,這樣連請求都不用,直接呼叫函式即可。

 

 

 

後記

這樣看起來好像不難對不對,小編也是這麼想。

但是不知道網路上為什麼就是沒有人給出這樣的解法,都只能看到使用 forReference() 的方法,最後小編是跑去 Wicket 9.x API 裡面瞎找,結果還真的讓小編找到了(org.apache.wicket.markup.head.CssHeaderItem)。

沒錯,forUrl() 跟 forReference() 是同一個 class 下的函式,但是卻沒有人提及,想想也是搞笑,因為官方的文檔裡面也是使用 forReference()

END

你可能感興趣的文章

【Maven】如何創建一個簡單可部屬的WAR檔 滿重要的一個大功能,在使用JAVA網頁伺服器的時候一定會需要這個WAR檔來進行部屬

【Discord bot】[botton]按鈕的使用、響應和關閉 Discord的botton通常都要和View配合使用。

【Wildfly/jBoss】[Linux](Connection Datasource)如何與MySQL資料庫建立連線 網頁瀏覽器和資料庫的關係密不可分,而通常會將兩者分開架設在不同的伺服器上面來提供服務,這時要如何進行連線呢?

【C】(%c, %d)解決讀取字元時的緩衝區殘留 不解決就會莫名其妙地冒出一些莫名其妙的東西

【CoreProtect】[SpigotMC] (進階篇) 如何直接存取資料 大家好,這裡是準備要去參加FF38的小編過路君子 本來只要自己去,結果臨時有人說要一起去,那...好吧!走~ 對於一般人

【Minecraft】[CoreProtect|BungeeCord]如何重新命名世界或維度名稱 當只有一個伺服器的時候,問題往往處理起來非常簡單,但是一旦當伺服器成長至兩台以上,事情便開始有趣了起來

我有話要說

>>

限制:留言最高字數1000字。 限制:未登入訪客,每則留言間隔需超過10分鐘,每日最多5則留言。

訪客留言

[無留言]

隨機好文

[活動] 2017年4/1雲空幻想愚人節活動彩蛋&攻略 (紀念性質) 雲空幻想2017年的愚人節活動介紹同時也是本小編的第一篇網路文章(*^ω^)♪

高捷少女:布拉格體驗㊦ 「各位想到盧卡站的乘客,請到我們左手邊排隊!」婕兒大聲地喊道。     「這孩子怎麼穿著地鐵站制服?童工嗎?」一位大嬸歪頭問道。

高捷少女:地下城的探險少女(終)  小穹眨眨眼睛,然後說了出來。「其實,從剛剛開始,我就在想了……是在看過這本日記之後。」她拿出日記。「我想……我們尋找寶藏的想法,是不是真的正確的?」「怎麼說呢?」耐耐好奇地問。「這個埋藏寶藏的人,在

高捷少女:美麗島的守護者④ 光之穹頂的某處垃圾桶底,一個四方形的機器持續發出聲音,機器的儀表板上顯示著「1:25:10」的字樣,外表被一層鞭炮所掩蓋。儀表板的數字每秒不斷減少,細微的嗶嗶聲也隨著數字的改變發出,但在熙來攘往的美麗

高捷少女:耐耐的新年驚喜③ 即使如此,夫人仍然每年都會問老爺是否能空出一週時間,但總是被回絕,除了前年以外。老爺答應夫人一定會排出空檔,他們在去年的二十三日前往澳洲。」耐耐嘆了口氣。「那一天的晚上,我打電話給媽媽時,她很高興地告