unverbuggt / mkdocs-encryptcontent-plugin

A MkDocs plugin that encrypt/decrypt markdown content with AES
https://unverbuggt.github.io/mkdocs-encryptcontent-plugin/
MIT License
123 stars 15 forks source link

Password inventory #44

Closed unverbuggt closed 12 months ago

unverbuggt commented 1 year ago

The idea of using tags (jinja?) as a meta tag for the plugin is very good and if it is possible/works is much better than my idea.

But juste another idea (I have not tested/try anything). Maybe users want to use multiple methods (env/tags) for page encryption. And with this logic, the priority of one method over another should be removed in favor of a password inventory. Inventory could (potentially) be an extra key to add to the global "mkdocs.config" navigation menu (nav:). It would allow to have a list of passwords per page, to be used (always with the 3 basic cases, global/specific/absent) and for each of this password to use the env method OR the tag method. From a management point of view, it allows you to centralize passwords. From a security point of view, there is no real loss since currently if the source repository is accessible the passwords too. From a code point of view, you have to change a lot of things ^^'

Thank you for the continuous improvements of this plugin !

Originally posted by @CoinK0in in https://github.com/unverbuggt/mkdocs-encryptcontent-plugin/issues/43#issuecomment-1397571905

unverbuggt commented 1 year ago

You're welcome.

I like your idea and want to summarize my thoughts on this:

It maybe should also rate the used passwords and put out a warning if they are too weak. We must be aware that encryptcontent protected pages do not hinder offline brute force attacks, so the information is only as safe as the password used (when it comes to passwords, length is all that matters, really).

Also, I do believe that environment variables are not 100% secured from being read by other processes or even other users on the same system, so you need to trust your system and everyone who uses it. More secure would be to request password as text input on build (okay, there are keyloggers) and compare the input to a hash value saved beforehand to avoid mistyping.

CoinK0in commented 1 year ago

Thank you for opening a new "improvement".

introduce a new key in central mkdocs.yml file where password sources for different kinds of protection levels are defined. protection level may be a number or a string (f.ex. confidential, top secret, classified).

For this part, it is possible to introduce different level of encryption depending on the desired level of security (Good idea), but to kept it simple, I was thinking of adding an additional key to the basic navigation menu of mkdocs.yml, which is exploitable by all the current methods of the plugin (Add Env/TagMeta to define password, and use it as Specific in some case).

password sources may include: text, environment variable, password manager api?, keyring api?, console input

Interesting, on the other hand I think that the management of the "Password manager" is excluded cause the method of detection/identification/filling of the fields concerned are already included in the password manager. For the "keyring API" parts (if you are thinking of vaults) indeed very interesting to add a way to fill in a "vault" source. But there are so many that seem very complicated. And for the "console input" I think's that the process is slow/boring and I'm not sure that it brings more value compared to the development time. Maybe if someone ask it in the futur...

introduce new markdown meta tag where protection level can be set for each page. (not braking compatibility)

Might as well do that, as long as add an additional key in the menu definition, but it will always require a default order in case it is not defined.

It maybe should also rate the used passwords and put out a warning if they are too weak. We must be aware that encryptcontent protected pages do not hinder offline brute force attacks, so the information is only as safe as the password used (when it comes > to passwords, length is all that matters, really).

This is a good idea, as long as this process is done offline (on the build machine). Afterwards I do not agree that the length defines strength (it's rather the "entropy" which takes precedence from my point of view). For example AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (30*A - 8 bits entropy) is always weaker than åøÜÒÛ¹ä (93 bits entropy).

Also, I do believe that environment variables are not 100% secured from being read by other processes or even other users on the same system, so you need to trust your system and everyone who uses it. More secure would be to request password as text input on build (okay, there are keyloggers) and compare the input to a hash value saved beforehand to avoid mistyping.

Personally I wouldn't spend time to developing this feature cause I'm lazy. The fact is at the creation of this plugin access to sources by an malicious third party has always been a problem. Your method corrects this specific point, but again (from my point of view), it's really necessary to push your development so far, if the person is not able to protect the source ?

unverbuggt commented 1 year ago

Could you write a short example mkdocs.yml of how you'd picture it?

Something like this?

nav:
    - Short title: /path/to/page.md
        encrypt: !ENV [ENCRYPTCONTENT_PASSWORD, ''] #fallback is not to encrypt?!
    - Subcategory:
        - Another short title: /path/to/another_page.md
            encrypt: 'another password'
        - And another one: /path/to/and_another_page.md
            encrypt: 
              - !ENV [ENCRYPTCONTENT_PASSWORD, '']
              - [fallback_to_another_source]

But maybe I'm doing the spaces of the subkeys wrong... I'll have to try the correct syntax and test how to read the value in the plugin.

Adding third party "trusted" password sources (could be f.ex. yubikey) was just an idea, but as you were saying, the person has the plaintext right on his computer - unprotected. He could however place the plaintext site inside veracrypt/encfs to achieve additional protection. Maybe an idea for the future - if there are easy to interface safe password vaults.

Calculating the entropy of the used passwords offline should be not that hard. I agree, entropy is all that matters in the end, but it's easier to achieve high entropy by password length rather than adding additional characters to the mix.

CoinK0in commented 1 year ago

I tried my ideas as I thought I would do the trick (In the style of your above config), like :

nav:
  - Home: index.md
    encrypt: 321

But it seems it's not allowed in mkdocs . . . https://github.com/mkdocs/mkdocs/blob/c99ec45a320194d8f05f6f7124656294e3cb8098/mkdocs/config/config_options.py#L800-L813 🙃

And I didn't manage to overwrite the check function .. anyway it was not a great idea.

Afterwards, it would be possible to duplicate the keys of the navigation part, to put them in the configuration of the plugin, like :

nav:
  - Page1: page1.md
  - Page2: page2.md
  - Page3: page3.md
plugins:
  - encryptcontent:
      nav_password:
        - Page1: ENV ENCRYPTCONTENT_HOME_PASSWORD  # Use ENV variable to encrypt this page
        - Page2: password # Use this password to encrypt this page
        # Page3 will be encrypted with the meta tag in the article if it exists or the global password (From var or tag).

And then in the code, do a "if the "name" of the page match with an entry of nav_password" identify the method and encrypt the page. But I find it dirty to duplicate article name.

unverbuggt commented 1 year ago

mh, I see a problem when it comes to names (Page1) or markdown files (page1.md). The names could have duplicates on different parts/levels of the nav tree (or have different names: i18n) and what happens if you decide to move a markdown file and forget to change nav_password (also what happens if one of the nav_passwords is not used?).

plugins:
  - encryptcontent:
      password_levels:
        confidential: !ENV [ENCRYPTCONTENT_PASSWORD, ''] #won't raise an error if env not found -> also won't encrypt if not found
        top_secret:
          - !ENV [SUPERSECRET_PASSWORD] #won't build if env not found
        classified:
          - {other_source_of_password} #future use
          - 'test1234'

This way it would be possible to either define one password per level or a fallback order. Currently, I see no distinct use in a fallback order, as it is possible to define a fallback value using !ENV already (and we currently only have password string and env as options). So maybe the option to define a (fallback) list is currently of no direct use.
But I've seen an issue with the idea to define multiple passwords per page (so one could hand out multiple passwords to people and revoke/remove passwords later for reasons™). For this, I'd encrypt the page with a random password and encrypt this password for all other passwords in the list (and try them all when decrypting).

To actually use the password_levels one could write password_level: classified as meta tag in markdown. This would have the benefit that there is only one place where all passwords (or their sources) are defined: mkdocs.yml.

unverbuggt commented 1 year ago

I'll create a 2.5.x branch to test this and other changes