From 8a3a99f05de8f16c9e5505f9f287cc5b5d232f74 Mon Sep 17 00:00:00 2001 From: Cristina Date: Tue, 18 Feb 2020 15:17:03 -0800 Subject: [PATCH] Automated detection of malware: add documentation. Fixes #7095. (#7369) * Add documentation. Fixes #7095. * Add github issue template for contributing a malware check * Add docs and flow chart images * Code review cleanup. - Use correct casing for Warehouse - Formatting fixes - Additional clarifications * Fix ordered list formatting * Code review changes * fix formatting and add details about the classmethod Co-authored-by: Ernest W. Durbin III --- .github/ISSUE_TEMPLATE/malware-check.md | 16 ++ docs/_static/check-lifecycle.png | Bin 0 -> 25420 bytes docs/_static/verdict-lifecycle.png | Bin 0 -> 36636 bytes docs/application.rst | 6 +- docs/development/index.rst | 1 + docs/development/malware-checks.rst | 194 ++++++++++++++++++++++++ docs/security.rst | 5 + 7 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/malware-check.md create mode 100644 docs/_static/check-lifecycle.png create mode 100644 docs/_static/verdict-lifecycle.png create mode 100644 docs/development/malware-checks.rst diff --git a/.github/ISSUE_TEMPLATE/malware-check.md b/.github/ISSUE_TEMPLATE/malware-check.md new file mode 100644 index 000000000000..618015ec083d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/malware-check.md @@ -0,0 +1,16 @@ +--- +name: Malware Check +about: Contribute an new automated malware check to PyPI + +--- + +**Describe the proposed check** + + +**What kind of attack does this check detect?** + + +**Additional context** + + +* [ ] I agree to document this malware check in `docs/development/malware-checks.md` diff --git a/docs/_static/check-lifecycle.png b/docs/_static/check-lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..108e2177d437b3f45513307c9abca98cf46d7e83 GIT binary patch literal 25420 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 f+&LrO+Y^NvqsF@TaM&r&6tSKjMD??H9R- literal 0 HcmV?d00001 diff --git a/docs/_static/verdict-lifecycle.png b/docs/_static/verdict-lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..a43b934480df33242cfafb4efacd2977506f08f3 GIT binary patch literal 36636 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 - internationalization - `legacy/ `_ - most of the read-only APIs implemented here - `locales/ `_ - internationalization + - `malware/ `_ - automated malware checks - `manage/ `_ - logged-in user functionality (i.e., manage account & owned/maintained projects) - `metrics/ `_ - services for recording metrics diff --git a/docs/development/index.rst b/docs/development/index.rst index c9c4ddf97559..25d1e21e75ef 100644 --- a/docs/development/index.rst +++ b/docs/development/index.rst @@ -30,6 +30,7 @@ or the `pypa-dev mailing list`_, to ask questions or get involved. reviewing-patches legacy-application-structure development-database + malware-checks .. _`GitHub`: https://github.com/pypa/warehouse .. _`"What to put in your bug report"`: http://www.contribution-guide.org/#what-to-put-in-your-bug-report diff --git a/docs/development/malware-checks.rst b/docs/development/malware-checks.rst new file mode 100644 index 000000000000..1f8d8c7c2961 --- /dev/null +++ b/docs/development/malware-checks.rst @@ -0,0 +1,194 @@ +Malware Checks +============== + +.. contents:: + :local: + +Overview +------------ +This is a high-level diagram of the automated malware check system. + +|VerdictLifecycle| + +Checks can be triggered in the following ways: + +* A PyPI user uploads a new File, Release or Project; +* A schedule; +* A PyPI administrator initiates an evaluation run. + +All of the above triggers call the `IMalwareCheckService`_ factory to determine +how to execute the check. On production, the `DatabaseMalwareCheckService`_ is +returned, which runs the check and produces one or more verdicts. PyPI +administrator and moderators continuously review verdicts in the Warehouse +admin, make determinations about the accuracy of checks, and take further action +if needed (e.g. to remove a malicious package surfaced by a verdict). + +Contributing +------------ + +Check Lifecycle +~~~~~~~~~~~~~~~ +|CheckLifecycle| + +Ideas for new malware checks should first be shared by `opening an issue`_. +This will initiate a discussion with PyPI administrators and among the broader +Python community about the impact of the proposed check. After soliciting +feedback, `open a pull request to master`_ containing the code for the new check, +unit tests, and accompanying documentation. Once the code is reviewed and merged, +it will automatically be deployed to production. PyPI administrators can begin +evaluating the malware check by moving it into the `evaluation` state in the check +admin and triggering an evaluation run. + +The evaluation run generates verdicts, which are viewable in the verdicts +admin. After reviewing the verdicts, the administrator will make a determination +and communicate it to the check developer in the initial issue. Here are the +possible outcomes: + +* The check provides a low-quality or noisy signal (e.g. many false positives), + and should be removed. At this point, the check will be moved into a + ``wiped_out`` state, removing all verdicts generated by the evaluation run, + and the code for the check will be removed in the next release. +* The check provides a useful signal, but requires modifications. The + administrator will request changes in the initial issue. +* The check provides a useful signal, and the administrator enables it. + +Adding New Checks +~~~~~~~~~~~~~~~~~ +All active checks are defined as classes in the `warehouse/malware/checks/`_ +directory, and exported from ``__init__.py``. The checks in +`tests/common/checks/`_ can serve as templates for developing new checks. Simply +copy/paste the desired check template into `warehouse/malware/checks/`_ and edit +the `dunder init file`_ to get started. Complex checks that consist of more than +a signle file should be housed in a subdirectory of `warehouse/malware/checks/`_. + +All malware check classes should inherit from +``warehouse.malware.checks.base.MalwareCheckBase``, define a `scan` method, and +set the following fields as class attributes: + +* ``version`` - ``1`` for new checks, incrementing by one with every subsequent + change +* ``short_description`` - a terse description of the check's purpose +* ``long_description`` - a more detailed rationale for the check +* ``check_type`` - either ``"event_hook"`` or ``"scheduled"`` + +For each check type, there is an additional required attribute: + +* ``hooked_object``- only for ``event_hook`` checks. The name of the object + whose creation triggers a check run. Currently ``"File"``, ``"Release"``, and + ``"Project"`` are supported. +* ``schedule`` - only for ``scheduled`` checks. This should be represented as a + dictionary that is passed to a `celery crontab`_. + +The `prepare classmethod`_ in ``MalwareCheckBase`` is called as part of every +check execution, and contains the logic for building ``**kwargs`` that are +passed to the check-defined ``scan`` method. ``prepare`` can be modified to +supply additional keyword arguments for complex checks. Currently, it populates +the following ``kwargs`` for ``"event_hook"`` checks: +* ``obj_id``: the id of the ``hooked_object`` +* ``file_url``: the file url when the ``hooked_object`` is a ``File`` + +All verdicts **must** be associated with a particular object. For +``"event_hook"`` checks, the ``obj_id`` should be propogated to verdicts +generated by that check. The `MalwareVerdict model`_ contains more information +about required and optional verdict fields. + + +Modifying Existing Checks +~~~~~~~~~~~~~~~~~~~~~~~~~ +Every time that the code for an existing check is modified, the developer +should increment the check version number. This is to ensure that each verdict +is associated with a particular version of a check. + +Workflow and Testing +~~~~~~~~~~~~~~~~~~~~ +There are a few steps for executing new malware checks in a development +environment: + +#. Complete the `Getting Started`_ instructions to setup a Warehouse + development environment +#. Open `dev/environment`_ and set the ``MALWARE_CHECK_BACKEND`` variable + + .. code-block:: bash + + MALWARE_CHECK_BACKEND=warehouse.malware.services.DatabaseMalwareCheckService + + In the development environment, Warehouse by default will only print the name + of the queued check instead of executing it. + +#. Add your new malware check to the database. + + .. code-block:: bash + + docker-compose run web python -m warehouse malware sync-checks + +#. Start Warehouse + + .. code-block:: bash + + make serve + +#. Login to Warehouse in the browser as ``ewdurbin:password`` and navigate + to ``/admin/checks`` +#. Click on the check name and set the check state to ``evaluation`` +#. Run an evaluation +#. View the results of the evaluation at ``/admin/verdicts`` +#. For hooked checks, it may be useful to run the check against an object (e.g. + File, Release, or Project) that triggers a ``threat`` verdict. Set the check + state to "enabled" in the check admin and upload some malicious content with + `twine`_. For example, if you're running Warehouse locally, upload a + malicious file by running the following command from the directory containing + your built package. + + .. code-block:: bash + + twine upload --repository-url http://localhost/legacy/ dist/* + +Once you've manually validated the basic functioning of your check, add tests +to the `tests directory`_. See `Submitting Patches`_ for more information about +how to contribute. + +Existing Checks +--------------- +Currently, there are two enabled checks in Warehouse. + +SetupPattenCheck +~~~~~~~~~~~~~~~~ +`SetupPatternCheck`_ is an ``"event_hook"`` check that scans the ``setup.py`` +file of source distributions upon file upload for potentially malicious code +that would execute automatically upon package install. + +PackageTurnoverCheck +~~~~~~~~~~~~~~~~~~~~ +`PackageTurnoverCheck`_ is a ``"scheduled"`` check that runs daily to look for +suspicious user behavior around package ownership. + +Historical Context +------------------ + +In September 2019, the Python Software Foundation issued a +`Request for Proposal`_ for a system to automate the detection of malicious +uploads. This system was initially rolled out in February 2020 by +`pull request 7377`_. + + +.. |VerdictLifecycle| image:: ../_static/verdict-lifecycle.png +.. _IMalwareCheckService: https://github.com/pypa/warehouse/blob/master/warehouse/malware/interfaces.py +.. _DatabaseMalwareCheckService: https://github.com/pypa/warehouse/blob/master/warehouse/malware/services.py +.. _celery crontab: http://docs.celeryproject.org/en/latest/reference/celery.schedules.html#celery.schedules.crontab +.. _prepare classmethod: https://github.com/pypa/warehouse/blob/master/warehouse/malware/checks/base.py +.. _MalwareVerdict model: https://github.com/pypa/warehouse/blob/master/warehouse/malware/models.py +.. |CheckLifecycle| image:: ../_static/check-lifecycle.png +.. _opening an issue: https://github.com/pypa/warehouse/issues/new?template=malware-check.md +.. _open a pull request to master: submitting-patches/ +.. _tests/common/checks/: https://github.com/pypa/warehouse/tree/master/tests/common/checks/ +.. _warehouse/malware/checks/: https://github.com/pypa/warehouse/tree/master/warehouse/malware/checks +.. _dunder init file: https://github.com/pypa/warehouse/tree/master/warehouse/malware/checks/__init__.py +.. _Getting Started: ../getting-started/#detailed-installation-instructions +.. _dev/environment: https://github.com/pypa/warehouse/tree/master/dev/environment +.. _twine: https://twine.readthedocs.io/en/latest/ +.. _tests directory: https://github.com/pypa/warehouse/blob/master/tests/unit/malware/checks +.. _Submitting Patches: submitting-patches/ +.. _SetupPatternCheck: https://github.com/pypa/warehouse/blob/master/warehouse/malware/checks/setup_patterns/check.py +.. _PackageTurnoverCheck: https://github.com/pypa/warehouse/blob/master/warehouse/malware/checks/package_turnover/check.py +.. _Request for Proposal: https://github.com/python/request-for/blob/master/2019-Q4-PyPI/RFP.md#milestone-2---systems-for-automated-detection-of-malicious-uploads +.. _pull request 7377: https://github.com/pypa/warehouse/pull/7377 diff --git a/docs/security.rst b/docs/security.rst index 3590553eec37..10b84fe48817 100644 --- a/docs/security.rst +++ b/docs/security.rst @@ -13,3 +13,8 @@ Project and release activity details ------------------------------------ See :doc:`api-reference/feeds` for how to track new and updated releases on PyPI. + +Malware Checks +-------------- +See :doc:`development/malware-checks` for information about existing checks +that are instrumented in PyPI, and instructions for contributing new checks.