SessionStorage 和 LocalStorage 以及 XSS攻击,看这一篇就够了

1.SessionStorage和LocalStorage介绍

在HTML5之前,开发人员一般是通过使用Cookie在客户端保存一些简单的信息的。在HTML5发布后,提供了一种新的客户端本地保存数据的方法,那就是Web Storage,它也被分为:LocalStorage和SessionStorage,它允许通过JavaScript在Web浏览器中以键值对的形式保存数据。而相比Cookie有如下优点:

  1. 拥有更大的存储容量,Cookie是4k,Web Storage为5M。
  2. 操作数据相比Cookie更简单。
  3. 不会随着每次请求发送到服务端。

1.1如何使用SessionStorage和LocalStorage

您可以使用浏览器window对象访问SessionStorage和LocalStorage。请看下面的示例:

sessionStorage = window.sessionStorage
localStorage = window.localStorage

//存储一个item
  storage.setItem('name', 'Alice')
  storage.setItem('age', '5')
//读取一个item
  storage.getItem('name') // returns "Alice"
//get存储对象长度
  storage.length // returns 2
//通过索引get对应的key名
  storage.key(0) // returns "name"
//移除一个item
  storage.removeItem('name')
//清空存储对象
  storage.clear()

1.2 LocalStorage与SessionStorage的区别

LocalStorage和SessionStorage之间的主要区别在于浏览器窗口和选项卡之间的数据共享方式不同。

LocalStorage可跨浏览器窗口和选项卡间共享。就是说如果在多个选项卡和窗口中打开了一个应用程序,而一旦在其中一个选项卡或窗口中更新了LocalStorage,则在所有其他选项卡和窗口中都会看到更新后的LocalStorage数据。

但是,SessionStorage数据独立于其他选项卡和窗口。如果同时打开了两个选项卡,其中一个更新了SessionStorage,则在其他选项卡和窗口中不会反映出来。举个例子:假设用户想要通过两个浏览器选项卡预订两个酒店房间。由于这是单独的会话数据,因此使用SessionStorage是酒店预订应用程序的理想选择。

1.3 安全性说明

Web Storage的存储对象是独立于域名的,也就是说不同站点下的Web应用有着自己独立的存储对象,互相间是无法访问的,在这一点上SessionStorage和LocalStorage是相同的。

举个例子:部署在abc.com上的Web应用无法访问aoe.com的Web Storage存储对象。

同样,对于子域名也是一样,尽管www.aoe.com 和 nihao.aoe.com 同属 aoe.com主域下,但它们相互不能访问对方的存储对象。

另外,不仅对子域名相互独立,对于针对使用http和https协议间也是不同的,所以这一点也需要注意。

1.4 应对跨站点脚本攻击(XSS)

首先,什么是XSS攻击?

XSS是将一段恶意脚本添加到网页上,通过浏览器加载而执行从而达到攻击并获得隐私信息的目的。

LocalStorage和SessionStorage在这一点上都容易受到XSS攻击。攻击者可直接向存储对象添加恶意脚本并执行。因此不太建议把一些敏感的个人信息存储在Web Storage中,例如:

  • 用户名密码

  • 信用卡资料

  • JsonWeb令牌

  • API密钥

  • SessionID

1.5 如何避免攻击?

  • 尽量不要用同一域名部署多个Web应用程序,如果有这种场景请尽量使用子域名部署应用,因为一旦多应用使用统一的域名,这将会对所有的用户共享Web存储对象。
  • 一旦将数据存储在LocalStorage中,开发人员在用户将其清除之前无法对其进行任何控制。如果希望在会话结束后自动删除数据,请使用SessionStorage。
  • 从WebStorage读取出的数据都要验证、编码和转义。
  • 在保存进WebStorage前将数据加密。

1.6 使用存储对象进行浏览器缓存

一般情况下,我们可以缓存一些应用数据,以便后面供Web应用使用。例如,你的Web应用需要加载所有国家的货币数据,在不使用WebStorage情况下,每次加载获取列表时都需要发出HTTP请求来获取,而将数据保存在LocalStorage后,可直接获取数据。

由于LocalStorage不会过期的特性,用户在任何使用打开页面时都可以使用存储对象中的内容,而如果用户想删除LocalStorage数据也很简单,清除浏览器缓存内容即可。

1.7 监听LocalStorage变化

LocalStorage是一个可以用作本地持久化存储的对象,我们可以向其中添加数据存储,同样它在用户操作的情况下发生变化时,我们也需要能监听到,当它发生变化时,会触发storage事件,我们可以在window上监听到这个事件,从而完成一些逻辑操作。  

window.addEventListener('storage', () => {
  ...
});
    
 window.addEventListener('storage', () => {
  ...
}); 

您可以根据您的使用情况选择LocalStorage与SessionStorage。如果您的应用程序需要在多个浏览器窗口和标签页中共享数据,请使用LocalStorage,否则请使用SessionStorage。

SessionStorage和LocalStorage都容易受到XSS攻击。因此,请避免将敏感数据存储在浏览器存储中。

最后,虽然WebStorage很好用,还是建议你在如下的情况下使用:

  • 没有敏感数据
  • 数据尺寸小于 5MB
  • 高性能并不重要

2.electron中使用LocalStorage与SessionStorage

通过webContents.executeJavaScript();对LocalStorage与SessionStorage进行操作。本例主窗体为BrowserWindow(mainWindow)加载BrowserView (view)。所以访问对象是view。

app中监听页面新增,并在新增中监听新开window。在新开window中webContents.on('did-start-loading')读取主窗体SessionStorage。

let mystorage=require('./src/plugin/myStorage')

app.on('web-contents-created', (e, webContents) => { 
    webContents.on('new-window', (event, url) => {  
        //其他业务判断。
        CreateNewWin(url);
    });
});  
   function CreateNewWin(url) { 
        let nwin = new BrowserWindow({ 
            icon: path.join(__dirname, 'static/img/win.ico'),
            webPreferences: {
                show: false,
                preload: path.join(__dirname, './src/renderer/toolbar.js'),
                webviewTag: true,
                nodeIntegration: false, //不是用elec
                contextIsolation: false, //不设置不能调用js文件
                webSecurity: false, //v9.0以下版本才可以
                allowRunningInsecureContent: true,
                allowDisplayingInsecureContent: true, 
            }
        })
        nwin.maximize();
        nwin.show();
        Menu.setApplicationMenu(null); 
        nwin.webContents.loadURL(url); 
        nwin.webContents.on('did-start-loading',function(){
            mystorage.sessionStorage(view).length().then(r=>{ 
                for(let i=0;i<r;i++){
                    let k;
                    mystorage.sessionStorage(view).key(i).then(r=>{k=r;mystorage.sessionStorage(view).getItem(k).then(r=>{ mystorage.sessionStorage(nwin).setItem(k,r);}); }); 
                }
            })
            .catch(r=>{
                log.warn(r);
            });

        });  
        nwin.webContents.on('did-finish-load', (event, errorCode) => {
            nwin.title = apptitle
        }); 
        nwin.title = apptitle 
}

myStorage.js

const { app } = require('electron');

// Create an empty BrowserWindow to access browser storage
let storageWindow;
 
 
// Executes code in the BrowserWindow
function execute(code) {
  if (!app.isReady()) {
    throw Error('Storage methods can only be called after the app is ready.')
  }

  if (!storageWindow) {
    throw Error('Storage window is not initialized.')
  } 
  console.log(code);
  return storageWindow.webContents.executeJavaScript(code);
}

function Storage(storageName,win) {
    storageWindow=win
  /**
   * Returns the number of items in the storage
   */
  this.length = () => execute(`window.${storageName}.length;`);

  /**
   * Returns the key at the given index
   * @param {number} index Index to get
   */
  this.key = index => execute(`window.${storageName}.key('${index}');`);

  /**
   * Returns the value for the given key
   * @param {string} key Key to get
   */
  this.getItem = key => execute(`window.${storageName}.getItem('${key}');`);

  /**
   * Sets the value for the given key
   * @param {string} key Key to set
   * @param {*} value Value to set
   */
  this.setItem = (key, value) => execute(`window.${storageName}.setItem('${key}', '${value}');`);

  /**
   * Removes the item at the given key
   * @param {string} key Key to remove
   */
  this.removeItem = key => execute(`window.${storageName}.removeItem('${key}');`);

  /**
   * Removes all keys and values
   */
  this.clear = () => execute(`window.${storageName}.clear();`);
}

/**
 * localStorage object
 */
module.exports.localStorage =function(win){return new Storage('localStorage',win);}

/**
 * sessionStorage object
 */
module.exports.sessionStorage =function(win){return new Storage('sessionStorage',win);} 
posted @ 2022-02-24 10:01  waleswood  阅读(1668)  评论(0编辑  收藏  举报