Security

A mailer, member database, and so much more, for digital activism.

Security

User Permissions

From version 20.11 onwards, there is a range of permissions you can grant to users with custom roles. Here is the current list of permissions relevant to members (as opposed to API users):

Permission name Description
super_admin Special: this grants all other permissions. Not recommended.
send_sms Allows sending SMS messages
sms Allows viewing and editing SMS messages before sending (usually used alongside send_sms)
imports Allows importing data (accessed via Admin > Settings > Imports), can import members, actions or donations
manage_variables Allows managing variables, accessed via Admin > Settings > Variables
read_mailings Allows reading mailings which have already been sent
send_mailings Allows sending mailings, includes editing, sending samples, scheduling and making recurring mailings
manage_members deprecated: use more granular member permissions instead (note: if you previously had this permission enabled, the migration enabled the more granular permissions instead)
view_members Allows viewing a single member, searching for a member by email or name.
update_member_details Allows updating a member’s details. Can update name, address, notes, member actions and phone numbers
update_member_subscriptions Allows toggling a member’s subscriptions (email, SMS, phone etc.) on or off, and unsubscribing permanently
anonymize_members Allows anonymizing (AKA ‘ghosting’) a single member, button appears on the member view page
bulk_update_members Allows certain bulk member operations (via lists and searches). Includes bulk subscription updating, bulk tag updates and bulk phone number operations
push_members_to_service Allows pushing members to a service
manage_searches Allows viewing, creating, editing and pushing to list for searches
upload_lists Allows creating a new list by submitting emails, phone numbers, IDs or GUIDs
read_lists Allows viewing all lists. (NOTE: Anyone can delete a list they created. Only super admins can delete other people’s lists)
download_lists Allows downloading a full list export
anonymize_lists Allows anonymizing (AKA ‘ghosting’) a list of members (can only be done on lists smaller than Settings.ghoster.bulk_max_members, which is 1,000 by default)
view_job_status Allows viewing job statuses, accessed via Admin > Settings > Job Statuses

You’ll need to use a rails console to create a custom role, with your desired permissions enabled. Here’s an example “staff” role with a wide range of permissions, but lacking the ability to perform some super admin and bulk operations:

Role.create!(description: 'Staff role', view_members: true, update_member_details: true, update_member_subscriptions: true, manage_searches: true, read_mailings: true, send_mailings: true, send_sms: true, sms: true, upload_lists: true, read_lists: true, view_job_status: true)

After you’ve created your custom role or roles, you can use it when adding new admin users. Updating an existing user’s role can be done with the rails console.

Security updates October 2020

Permission slugs are now permission booleans/attributes saved on roles. Any deployment which was updated to work with the update in July 2020 will still work, DB migrations will look after the translation from slugs to booleans. For orgs doing an update from 20.06.1 or earlier to this version or later, you can follow the same instructions with just one change, if you are creating API users with multiple permissions, follow this pattern (note the underscores _ instead of dashes - ):

speakout_user = APIUser.find_by(name: 'speakout')
speakout_user.update!(Role.create!(description: 'speakout api user')) if speakout_user.role.blank?
speakout_user.role.update!(members_api: true, donations_api: true, actions_api: true)

Security updates July 2020

The following webhook and other API endpoints are being tightened up in this release:

endpoint/s Previous security New security Permission slug
/nexmo/api/inbound_sms None token check nexmo-webhook
/plivo/api/inbound_sms None token check + HMAC check plivo-webhook
/twilio/api/inbound_sms None token check + HMAC check twilio-webhook
/paypal/ipn None token check paypal-webhook
/go_cardless/webhook HMAC check token check + HMAC check go-cardless-webhook
/stripe/webhook HMAC check token check + HMAC check stripe-webhook
/razorpay/webhook HMAC check token check + HMAC check razorpay-webhook
/api/ctrlshift_webhook IP restricted + (any) token check IP restricted + token check csl-webhook
/api/groups None token check groups-api
/api/lists None token check lists-api
/api/lists/* (any) token check token check lists-api
/api/actions (used by speakout) None token check actions-api
api/member_actions/* except /api/member_actions/feed (any) token check token check actions-api
/api/alexa/flash-briefing None token check actions-api
/api/campaigns/* (any) token check token check actions-api
/api/consents/ (any) token check token check members-api
/api/contributions/create (used by speakout) None token check donations-api
/api/events/upsert & /api/events_rsvp/upsert (any) token check token check events-api
/api/issues/list & /api/issue_categories/list (used by speakout) (any) token check token check actions-api
/api/mailjet/feedback-loop (any) token check token check mailjet-api
/api/member/* (used by speakout) (any) token check token check members-api
/api/regular_donations/create (any) token check token check donations-api
/api/searches/* (any) token check token check searches-api
/api/subscriptions/* (any) token check token check member-subscriptions-api
mailings/api/mailings/* except mailings/api/mailings/feedback-loop (any) token check token check mailings-api

It’s best to pay attention to these two settings:

These are both true by default. The simplest process is to add env variables for both set to false before deploying these changes:

heroku config:set REQUIRE_TOKEN_FOR_ALL_API_ROUTES=false REQUIRE_ROLE_FOR_ALL_API_USERS=false

Once deployed, if your log level is set at ‘warn’ or higher, you will see messages about your api routes being accessed without tokens, you can find them by searching for “Webhook endpoint in use without api token verification” and “Api Token in use with no role”. For each of the external services you use, you need to setup an APIUser with the correct permission. Here’s an example with the nexmo permission:

> APIUser.create_with_permission!('nexmo-webhook', name: 'nexmo', active: true).token

Now grab the token, and add it the end of the webhook saved in your 3rd party service with ?api_token=. For example your nexmo URL might look like https://<your_identity_domain>/nexmo/api/inbound_sms?api_token=0b61e8905bd247715d53ffb76b6f71c4c2a7c337eb6f8e8c70ec8e47f4ff09703c24b0a9b8463ccd8ba6b3c3748898605d9f3b1848276c9310068b2534b09eba.

Repeat this with all the endpoints you’re using. It’s best to leave your setup open for another day or two and keep an eye on your logs to see if any warnings are still coming through. Once you’re happy, remove your environment variables holding the endpoints open:

heroku config:unset REQUIRE_TOKEN_FOR_ALL_API_ROUTES REQUIRE_ROLE_FOR_ALL_API_USERS

Other specific examples

If you already have an APIUser in use by speakout, you can give it the necessary permissions like this:

speakout_user = APIUser.find_by(name: 'speakout')
speakout_permissions = %w(members-api donations-api actions-api).map { |slug| Permission.find_by!(permission_slug: slug) }
speakout_user.update!(role: Role.create!(description: 'speakout api user', permissions: speakout_permissions))

Other common examples: | Application | Permissions needed | |———————-|—————————————| | Speakout | members-api donations-api actions-api | | CSL (id integration) | members-api | | CSL (webhooks) | csl-webhook | | ECC | mailings-api searches-api lists-api | | Analytics | No API access needed |

Super Admin API user permissions

It is recommended that all API users are restricted to only those API endpoints they need to use for their functionality. In this way, even a token with substantial access (to, for example, update members and actions) cannot be used for other purposes without explicit changes by an identity admin. This is particularly important with the consideration of potential future API endpoints with new permissions.

However, if an org considers the risk acceptable, they can configure API Users with a super-admin permission, granting access to all current and future API endpoints. As this configuration is discouraged, it is not enabled by default so before creating an API User role with the super-admin permission, you must enable Settings.app.allow_super_api_users either via your org Settings file or the ALLOW_SUPER_API_USERS environment variable.

Openly Accessibly Identity endpoints

All identity controllers must call authorize unless they have skip_after_action :verify_authorized_with_fallback instead. As of this writing, these are the only publicly accessible identity endpoints:

Adding new routes & controllers (Pundit quicknotes)

If you are adding a new route or controller, it will need to be covered by a pundit policy, or explicitly skip authorization.

Member Data access

This is a list of all the possible ways that personal member data can be accessed via the Identity app, in rough order of increasing numbers of members

Configuring SSL/TLS Certs for RDS databases

If you are using an RDS database, but running your application somewhere else (heroku for example), you may want to configure the RDS CA cert so that your app accesses the database using SSL - this will prevent man in the middle (MITM) attacks.

The identity repo already has a copy of the root RDS CA cert for 2019 - 2022, so all you need to do is add the path to the cert to your database url as a query parameter - ?sslmode=verify-full&sslrootcert=db/rds-ca-2019-root.pem

NOTE: If your database is currently using the old 2015 CA cert, you should use the combined root cert - sslmode=verify-full&sslrootcert=db/rds-combined-ca-bundle.pem

Once you’ve updated your database URL and confirmed your app is still running OK, it’s worth updating your database parameters in RDS to force SSL usage - this means apps will never be permitted to connect in a way which is vulnerable to MITM attacks. You need to update the rds.force_ssl to 1.

Data Expiry and Ghosting / Anonymization

app/lib/ghoster.rb wipes almost all member data. Some is anonymized, some is deleted.

Member data not wiped by ghoster.rb includes: