Skip to content

Commit

Permalink
feat(m365): add sharepoint service with 4 checks (#7057)
Browse files Browse the repository at this point in the history
Co-authored-by: MarioRgzLpz <[email protected]>
Co-authored-by: HugoPBrito <[email protected]>
Co-authored-by: MrCloudSec <[email protected]>
  • Loading branch information
4 people authored and cesararroba committed Mar 3, 2025
1 parent 8ff0c59 commit d3dd164
Show file tree
Hide file tree
Showing 22 changed files with 1,167 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ def execute(self) -> List[CheckReportMicrosoft365]:
findings = []
auth_policy = entra_client.authorization_policy

report = CheckReportMicrosoft365(
metadata=self.metadata(),
resource=auth_policy if auth_policy else {},
resource_name=auth_policy.name if auth_policy else "Authorization Policy",
resource_id=auth_policy.id if auth_policy else "authorizationPolicy",
)

if auth_policy:
report = CheckReportMicrosoft365(
metadata=self.metadata(),
resource=auth_policy if auth_policy else {},
resource_name=(
auth_policy.name if auth_policy else "Authorization Policy"
),
resource_id=auth_policy.id if auth_policy else "authorizationPolicy",
)
if getattr(
auth_policy, "default_user_role_permissions", None
) and not getattr(
Expand All @@ -48,10 +49,7 @@ def execute(self) -> List[CheckReportMicrosoft365]:
report.status_extended = (
"App creation is not disabled for non-admin users."
)
else:
report.status = "FAIL"
report.status_extended = "Authorization Policy was not found."

findings.append(report)
findings.append(report)

return findings
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from prowler.providers.common.provider import Provider
from prowler.providers.microsoft365.services.sharepoint.sharepoint_service import (
SharePoint,
)

sharepoint_client = SharePoint(Provider.get_global_provider())
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Provider": "microsoft365",
"CheckID": "sharepoint_external_sharing_managed",
"CheckTitle": "Ensure SharePoint external sharing is managed through domain whitelists/blacklists.",
"CheckType": [],
"ServiceName": "sharepoint",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "Sharepoint Settings",
"Description": "Control the sharing of documents to external domains by either blocking specific domains or only allowing sharing with named trusted domains.",
"Risk": "If domain-based sharing restrictions are not enforced, users may share documents with untrusted external entities, increasing the risk of data exfiltration or unauthorized access.",
"RelatedUrl": "https://learn.microsoft.com/en-us/sharepoint/turn-external-sharing-on-or-off",
"Remediation": {
"Code": {
"CLI": "Set-SPOTenant -SharingDomainRestrictionMode AllowList -SharingAllowedDomainList 'domain1.com domain2.com'",
"NativeIaC": "",
"Other": "1. Navigate to SharePoint admin center https://admin.microsoft.com/sharepoint. 2. Expand Policies then click Sharing. 3. Expand More external sharing settings and check 'Limit external sharing by domain'. 4. Select 'Add domains' to configure a list of approved domains. 5. Click Save.",
"Terraform": ""
},
"Recommendation": {
"Text": "Enforce domain-based restrictions for SharePoint external sharing to control document sharing with trusted domains.",
"Url": "https://learn.microsoft.com/en-us/powershell/module/sharepoint-online/set-spotenant?view=sharepoint-ps"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from typing import List

from prowler.lib.check.models import Check, CheckReportMicrosoft365
from prowler.providers.microsoft365.services.sharepoint.sharepoint_client import (
sharepoint_client,
)


class sharepoint_external_sharing_managed(Check):
"""
Check if Microsoft 365 SharePoint external sharing is managed through domain whitelists/blacklists.
This check verifies that SharePoint external sharing settings are configured to restrict document sharing
to external domains by enforcing domain-based restrictions. This means that the setting
'sharingDomainRestrictionMode' must be set to either "AllowList" or "BlockList". If it is not, then
external sharing is not managed via domain restrictions, increasing the risk of unauthorized access.
Note: This check only evaluates the domain restriction mode and does not enforce the optional check
of verifying that the allowed/blocked domain list is not empty.
"""

def execute(self) -> List[CheckReportMicrosoft365]:
"""
Execute the SharePoint external sharing management check.
Iterates over the SharePoint settings retrieved from the Microsoft 365 SharePoint client and
generates a report indicating whether external sharing is managed via domain restrictions.
Returns:
List[CheckReportMicrosoft365]: A list containing a report with the result of the check.
"""
findings = []
settings = sharepoint_client.settings
if settings:
report = CheckReportMicrosoft365(
self.metadata(),
resource=settings if settings else {},
resource_name="SharePoint Settings",
resource_id=sharepoint_client.tenant_domain,
)
report.status = "FAIL"
report.status_extended = "SharePoint external sharing is not managed through domain restrictions."
if settings.sharingDomainRestrictionMode in ["allowList", "blockList"]:
report.status_extended = f"SharePoint external sharing is managed through domain restrictions with mode '{settings.sharingDomainRestrictionMode}' but the list is empty."
if (
settings.sharingDomainRestrictionMode == "allowList"
and settings.sharingAllowedDomainList
):
report.status = "PASS"
report.status_extended = f"SharePoint external sharing is managed through domain restrictions with mode '{settings.sharingDomainRestrictionMode}'."
elif (
settings.sharingDomainRestrictionMode == "blockList"
and settings.sharingBlockedDomainList
):
report.status = "PASS"
report.status_extended = f"SharePoint external sharing is managed through domain restrictions with mode '{settings.sharingDomainRestrictionMode}'."

findings.append(report)
return findings
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Provider": "microsoft365",
"CheckID": "sharepoint_external_sharing_restricted",
"CheckTitle": "Ensure external content sharing is restricted.",
"CheckType": [],
"ServiceName": "sharepoint",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "Sharepoint Settings",
"Description": "Ensure that external sharing settings in SharePoint are restricted to 'New and existing guests' or a less permissive level to enforce authentication and control over shared content.",
"Risk": "If external sharing is not restricted, unauthorized users may gain access to sensitive information, increasing the risk of data breaches and compliance violations.",
"RelatedUrl": "https://learn.microsoft.com/en-us/sharepoint/turn-external-sharing-on-or-off",
"Remediation": {
"Code": {
"CLI": "Set-SPOTenant -SharingCapability ExternalUserSharingOnly",
"NativeIaC": "",
"Other": "1. Navigate to SharePoint admin center https://admin.microsoft.com/sharepoint. 2. Click to expand Policies > Sharing. 3. Locate the External sharing section. 4. Under SharePoint, move the slider bar to 'New and existing guests' or a less permissive level.",
"Terraform": ""
},
"Recommendation": {
"Text": "Restrict external sharing in SharePoint to 'New and existing guests' or a more restrictive setting to enhance security.",
"Url": "https://learn.microsoft.com/en-us/powershell/module/sharepoint-online/set-spotenant?view=sharepoint-ps"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from typing import List

from prowler.lib.check.models import Check, CheckReportMicrosoft365
from prowler.providers.microsoft365.services.sharepoint.sharepoint_client import (
sharepoint_client,
)


class sharepoint_external_sharing_restricted(Check):
"""
Check if Microsoft 365 SharePoint restricts external sharing at organization level.
This check verifies that external sharing settings in SharePoint are configured to allow only "New and existing guests"
(i.e., ExternalUserSharingOnly), which enforces authentication and limits access to external users. If a more permissive
setting is used, legacy sharing may be allowed, increasing the risk of unauthorized data access.
"""

def execute(self) -> List[CheckReportMicrosoft365]:
"""
Execute the SharePoint external sharing restriction check.
Iterates over the SharePoint settings retrieved from the Microsoft 365 SharePoint client and generates a report
indicating whether external sharing is restricted to 'New and existing guests' (ExternalUserSharingOnly).
Returns:
List[Check_Report_Microsoft365]: A list containing a report with the result of the check.
"""
findings = []
settings = sharepoint_client.settings
if settings:
report = CheckReportMicrosoft365(
self.metadata(),
resource=settings if settings else {},
resource_name="SharePoint Settings",
resource_id=sharepoint_client.tenant_domain,
)
report.status = "FAIL"
report.status_extended = (
"External sharing is not restricted and guests users can access."
)

if settings.sharingCapability in [
"ExistingExternalUserSharingOnly",
"ExternalUserSharingOnly",
"Disabled",
]:
report.status = "PASS"
report.status_extended = "External sharing is restricted to external user sharing or more restrictive."

findings.append(report)
return findings
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Provider": "microsoft365",
"CheckID": "sharepoint_guest_sharing_restricted",
"CheckTitle": "Ensure that SharePoint guest users cannot share items they don't own.",
"CheckType": [],
"ServiceName": "sharepoint",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "Sharepoint Settings",
"Description": "Ensure that guest users in SharePoint cannot share items they do not own, preventing unauthorized disclosure of shared content.",
"Risk": "If guest users are allowed to share items they don't own, there is a higher risk of unauthorized data exposure, as external users could share content beyond intended recipients.",
"RelatedUrl": "https://learn.microsoft.com/en-us/sharepoint/external-sharing-overview",
"Remediation": {
"Code": {
"CLI": "Set-SPOTenant -PreventExternalUsersFromResharing $True",
"NativeIaC": "",
"Other": "1. Navigate to SharePoint admin center https://admin.microsoft.com/sharepoint. 2. Click to expand Policies then select Sharing. 3. Expand More external sharing settings and uncheck 'Allow guests to share items they don't own'. 4. Click Save.",
"Terraform": ""
},
"Recommendation": {
"Text": "Restrict guest users from sharing items they don't own to enhance security and prevent unauthorized access.",
"Url": "https://learn.microsoft.com/en-us/sharepoint/turn-external-sharing-on-or-off"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from typing import List

from prowler.lib.check.models import Check, CheckReportMicrosoft365
from prowler.providers.microsoft365.services.sharepoint.sharepoint_client import (
sharepoint_client,
)


class sharepoint_guest_sharing_restricted(Check):
"""
Check if Microsoft 365 SharePoint guest sharing is restricted.
This check verifies that guest users in SharePoint cannot share items they do not own.
When guest resharing is enabled, external users might share content they don't own,
increasing the risk of unauthorized data exposure. This control ensures that the setting
to prevent external users from resharing is enabled.
"""

def execute(self) -> List[CheckReportMicrosoft365]:
"""
Execute the SharePoint guest sharing restriction check.
Iterates over the SharePoint settings retrieved from the Microsoft 365 SharePoint client
and generates a report indicating whether guest users are prevented from sharing items they do not own.
Returns:
List[CheckReportMicrosoft365]: A list containing a report with the result of the check.
"""
findings = []
settings = sharepoint_client.settings
if settings:
report = CheckReportMicrosoft365(
self.metadata(),
resource=settings if settings else {},
resource_name="SharePoint Settings",
resource_id=sharepoint_client.tenant_domain,
)
report.status = "FAIL"
report.status_extended = "Guest sharing is not restricted; guest users can share items they do not own."
if not settings.resharingEnabled:
report.status = "PASS"
report.status_extended = "Guest sharing is restricted; guest users cannot share items they do not own."

findings.append(report)
return findings
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Provider": "microsoft365",
"CheckID": "sharepoint_modern_authentication_required",
"CheckTitle": "Ensure modern authentication for SharePoint applications is required.",
"CheckType": [],
"ServiceName": "sharepoint",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "critical",
"ResourceType": "Sharepoint Settings",
"Description": "Ensure that modern authentication is required for SharePoint applications in Microsoft 365, preventing the use of legacy authentication protocols and blocking access to apps that don't use modern authentication.",
"Risk": "If modern authentication is not enforced, SharePoint applications may rely on basic authentication, which lacks strong security measures like MFA and increases the risk of credential theft.",
"RelatedUrl": "https://learn.microsoft.com/en-us/graph/api/resources/sharepoint?view=graph-rest-1.0",
"Remediation": {
"Code": {
"CLI": "Set-SPOTenant -LegacyAuthProtocolsEnabled $false",
"NativeIaC": "",
"Other": "1. Navigate to SharePoint admin center https://admin.microsoft.com/sharepoint. 2. Click to expand Policies select Access control. 3. Select Apps that don't use modern authentication. 4. Select the radio button for Block access. 5. Click Save.",
"Terraform": ""
},
"Recommendation": {
"Text": "Block access for SharePoint applications that don't use modern authentication to ensure secure authentication mechanisms.",
"Url": "https://learn.microsoft.com/en-us/powershell/module/sharepoint-online/set-spotenant?view=sharepoint-ps"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from typing import List

from prowler.lib.check.models import Check, CheckReportMicrosoft365
from prowler.providers.microsoft365.services.sharepoint.sharepoint_client import (
sharepoint_client,
)


class sharepoint_modern_authentication_required(Check):
"""
Check if Microsoft 365 SharePoint requires modern authentication.
This check verifies that modern authentication is enforced for SharePoint applications in Microsoft 365.
Modern authentication leverages OAuth 2.0 and supports advanced security features such as multi-factor
authentication (MFA) and conditional access. Legacy authentication protocols (e.g., basic authentication)
do not support these features and increase the risk of credential compromise.
The check fails if modern authentication is not enforced, indicating that legacy protocols may be used.
"""

def execute(self) -> List[CheckReportMicrosoft365]:
"""
Execute the SharePoint modern authentication requirement check.
Iterates over the SharePoint configuration retrieved from the Microsoft 365 SharePoint client and
generates a report indicating whether modern authentication is required for SharePoint applications.
Returns:
List[CheckReportMicrosoft365]: A list containing the report object with the result of the check.
"""
findings = []
settings = sharepoint_client.settings
if settings:
report = CheckReportMicrosoft365(
self.metadata(),
resource=settings if settings else {},
resource_name="SharePoint Settings",
resource_id=sharepoint_client.tenant_domain,
)
report.status = "PASS"
report.status_extended = "Microsoft 365 SharePoint does not allow access to apps that don't use modern authentication."

# Legacy Auth being True means that SharePoint allow access to apps that do NOT use modern authentication
if settings.legacyAuth:
report.status = "FAIL"
report.status_extended = "Microsoft 365 SharePoint allows access to apps that don't use modern authentication."

findings.append(report)

return findings
Loading

0 comments on commit d3dd164

Please sign in to comment.