Home > other >  Is adding this "code playground" to my WordPress website a security risk?
Is adding this "code playground" to my WordPress website a security risk?

Time:04-11

So I'm planning to add this "code playground" kind of interactive code snippets demo to some tutorials on my website.

I was wondering if there were security risks here.

The code fields are editable.

Clearly people can inject JavaScript easily.

However, is that any different at all than when we inject JS from the console tab? Is there any security concerns here?

Thank you for any help with this.

PS. You can run the code snippet below, or see the codepen here : https://codepen.io/elementhow/pen/dyJKYoB

let examples = document.querySelectorAll(".prog-example");

examples.forEach((example, i, arr) => {
   let pres = example.querySelectorAll(".examples pre");
   if (pres.length < 1) document.querySelector('.examples').remove();
   let htmlOfPreview = example.querySelector(".preview-parent pre");
   let preview = example.querySelector(".preview");
   htmlOfPreview.innerHTML = escapeHTML(preview.innerHTML);
   htmlOfPreview.addEventListener('input',function(){
      preview.innerHTML = htmlOfPreview.textContent;
   });

   let CSSdiv = document.createElement("style");
   document.getElementsByTagName("head")[0].appendChild(CSSdiv);
   pres.forEach((pre, i, arr) => {
      pre.addEventListener("click", function () {
         arr.forEach((e) => e.classList.remove("label-active"));
         pre.classList.add("label-active");
         CSSdiv.innerHTML = pre.textContent;
      });
      pre.setAttribute('contenteditable',"");
      if (pre.hasAttribute("contenteditable")){
         pre.addEventListener('input', function(){
         CSSdiv.innerHTML = pre.textContent;
      });
      }
   });
   if (pres[0]) pres[0].click();
});

function escapeHTML(html) {
   return document.createElement("div").appendChild(document.createTextNode(html)).parentNode.innerHTML;
}
*, *::after {
   box-sizing: border-box;
}
.prog-example {
   display: flex;
   width: 100%;
   background:#cecece;
}
.prog-example .examples {
   max-height: 440px;
   overflow-y: auto;
   padding: 0 10px;
   background-color:#eee8ab;
   min-width:170px;
   position:relative;
}

.prog-example .preview-parent {
   margin: 10px;
   display: flex;
   flex-direction: column;
   flex-grow: 1;
}
.prog-example .examples pre {
   font-size: 12px;
   padding: 6px;
   border: 1px solid #999;
   margin: 14px 0;
   border-radius: 8px;
   cursor: pointer;
   background-color:#fff;
   min-width:170px;
}
.prog-example .examples pre[contenteditable]{
       /* cursor: text; */
}
.prog-example .examples pre.label-active {
   outline: 2px solid #333;
}
.prog-example .preview-parent pre {
   background-color: #eee;
   margin: 0 0 10px;
   padding: 0 10px;
   position:relative;
}
.prog-example .preview-parent .preview {
   border: 1px solid #999;
   flex-grow: 1;
   position:relative;
   min-height:130px;
   background-color:#fff;
}
.prog-example .preview-parent > pre::after,.prog-example .preview-parent .preview::after,  .prog-example .examples::after {
   content:'HTML';
   position:absolute;
   background-color:#777;
   font-family:monospace;
   font-size:13px;
   color:#fff;
   padding:4px;
    border-bottom-left-radius:6px;
   top:0;
   right:0;
}
.prog-example .preview-parent .preview::after {
   content:'PREVIEW';
}
.prog-example .examples::after {
   content:'CSS';
}

/* scroll bar if there is overflow */
.prog-example .examples::-webkit-scrollbar-track {
   background-color: #f4f4f4;
}
.prog-example .examples::-webkit-scrollbar {
   width: 6px;
   background-color: #f4f4f4;
}
.prog-example .examples::-webkit-scrollbar-thumb {
   background-color: #00000044;
}
<div >
   <div >
      <pre>
.test-button{
   font-size:16px;
}</pre>
      <pre>
.test-button{
   font-size:21px;
}      </pre>
      <pre>
.test-button{
   font-size:44px;
}      </pre>
      <pre>
.test-button{
   font-size:16px;
}</pre>
      <pre>
.test-button{
   font-size:21px;
}      </pre>
      <pre>
.test-button{
   font-size:44px;
}      </pre>
      <pre>
.test-button{
   font-size:16px;
}</pre>
      <pre>
.test-button{
   font-size:21px;
}      </pre>
      <pre>
.test-button{
   font-size:44px;
}      </pre>
      <pre>
.test-button{
   font-size:16px;
}</pre>
      <pre>
.test-button{
   font-size:21px;
}      </pre>
      <pre contenteditable>
.test-button{
   font-size:44px;
}      </pre>
      </div>
   <div >
      <pre contenteditable></pre>
      <div >
<div >
<button class='test-button'>click me</button>
</div>
         </div>
   </div>
   </div>

CodePudding user response:

Short answer: As long as there is no inputs that could send http requests to your server, it is all client side and safe.

Long:

In the HTTP world for an attack surface you need an "input field" (not UI element) where you can send some data that will be parsed by the server. This is done through http requests, where you put some data in the header and body, send them to the server and you expect some kind of response from the server. If you don't create policies for what forms of data is acceptable for the server, then it's possible to inject code that will make the server behave differently from the business logic.

In your case, you get the playground from the server, and the script in the playground runs on your browsers javascript engine (client side), but nothing is sent back to the server.

For example a big problem would be if without any security measure you could send back your malicious playground to the server to save it (like codepen). This way you can inject code on different levels: server framework, database (SQL injection). And if someone else is able to open your malicious playground then the dangerous script will run on their client side (XSS and CSRF attack).

So every input potentially a threat that you have to handle securely on the server-side by doing input sanitization and output escaping.

  • Related