Privacy Policy
Last updated: July 12, 2026
This Privacy Policy explains what information qMEET collects, how we use it, who can see it, and the choices you have. It applies to the qMEET website and app at qmeet.net. Using qMEET means you agree to this policy and to our Terms of Service.
The short version
- We collect what you give us — your account, profile, and the events, groups, and messages you create — plus basic technical data needed to run the site securely.
- We use it to operate qMEET: your account, events and groups, chat, member matching, reminders, and keeping the site safe.
- We do not sell your personal information, and we don’t show advertising.
- You decide who sees what. The Preferences page controls, field by field, who can see your name, age, gender, photos, interests, memberships, and status — and who can message you.
- You can reach us any time through Contact Us.
1. Who We Are & How to Contact Us
- qMEET is a community platform for discovering and organizing local events and groups, meeting people who share your interests, and chatting with them.
- qMEET (“we,” “us”) is responsible for the personal information described here. For any privacy question or request, reach us through the Contact Us page or by email at
ADMIN@qMeet.net.
2. Information We Collect
Information you give us
- Account: a username and password, and — for account recovery and notifications — your email address and/or mobile phone number.
- Profile: your first and last name, an optional date of birth (used only to show or verify your age; your actual birthday is never shown to others), gender, general location (city, state or region, ZIP/postal code, country), an “About Me,” the days and times you tend to be available, and any profile photos you upload.
- Your interests, which power event, group, and member suggestions.
- Content you create: events and groups you organize, RSVPs, one-to-one and group/event chat messages and any files you attach, survey questions and responses, check-ins, your contacts list, and any feedback you send us.
Information collected automatically
- When you visit key pages we record technical details in a security and audit log: your IP address, browser, operating system, device type, screen resolution, language, and time zone, along with the pages you visit and a session identifier. This is used to keep your account and the site secure and to investigate abuse or errors — never for advertising.
- We use cookies and browser storage that are necessary for the site to work (see Cookies & Browser Storage below).
Location information
- Check-ins. If you check in at a place (the “I’m Here” feature), where you checked in is shown to others according to the visibility you choose for “Status, Check-in & Photos” in Preferences (Any Member, Only My Contacts, or Nobody), and you can turn it off for individual contacts.
- Approximate device location. If you grant your browser’s location permission to qMEET (for example, after using a check-in), qMEET may update your approximate location periodically while the site is open, so location-aware features and your city/state work without prompting you again. Your coordinates are converted to a city and state using Google’s geocoding service; your precise location is visible only to site administrators, never to other members. You can stop this at any time by revoking qMEET’s location permission in your browser’s site settings.
- We also estimate an approximate city from your IP address using a geolocation database kept on our own server — your IP address is not sent to a third party for this.
Information from third parties
- If you choose to sign in with Google, Google provides the basic account information needed to create or match your qMEET account (such as your name, email address, and a Google account identifier). We never receive your Google password.
3. How We Use Your Information
- To run qMEET — create and secure your account, show and manage events and groups, deliver chat, rank member matches by shared interests, and remember your preferences.
- To personalize — suggest events, groups, and members near you or matching your interests, and show your city and state.
- To communicate with you — account, recovery, and security messages, plus reminders and notifications you control on the Notifications page.
- To keep everyone safe — detect and prevent abuse and spam, moderate content, enforce our Terms, rate-limit sensitive actions, and maintain a security audit trail.
- To improve qMEET and diagnose and fix problems.
4. How Your Information Is Shared
- With other members — only as you choose. What another member can see about you is governed by your per-field settings in Preferences. Each field can be shown to Anyone (including signed-out visitors), Any Member, Only My Contacts, or Nobody. You separately control who can message you, who can find you in search and Member Match, and who can see your profile and photos.
- We do not sell your personal information, and we do not share it for cross-context behavioral advertising.
- Service providers who help us operate specific features and receive only what that feature needs: Google (sign-in and location geocoding), OneSignal (push notifications), our email-delivery provider (to send account, recovery, reminder, and notification email), and AI providers used to power certain optional content features. They are not permitted to use your information for their own purposes.
- Site administrators can access account data, content, security logs, and precise location as needed to operate the service and to review reported or flagged content.
- Legal reasons — we may disclose information if required by law or to protect the rights, safety, and security of our users, the public, or qMEET.
- Aggregated or de-identified information that cannot reasonably identify you may be used without restriction.
5. Your Privacy Choices & Controls
- Who sees your profile — set visibility for your name, age, gender, interests, event and group memberships, availability, status/check-in, last-active time, profile, and photos in Preferences → Privacy.
- Who can contact or find you — choose who can message you, whether people find you by name or only by email/phone, and whether you appear in Member Match.
- Messages — set how long your direct messages are kept before they auto-delete in Preferences → Messages (pinned, saved, tagged, unread messages and open 🎯 action items are always kept).
- Notifications — choose your reminder channels and set Quiet Hours or Do Not Disturb on the Notifications page, and turn push notifications on or off at any time.
- Location — revoke qMEET’s location permission in your browser to stop approximate-location updates, and turn off status/check-in sharing for specific people from your Contacts or their profile.
- Account security — enable two-factor (email) verification and review your trusted devices in Preferences → Security; sign out your other devices from your account settings.
- Edit your information — update your profile, contact details, and photos on My Profile, and edit or delete the events, groups, and messages you created.
- Deactivate your account — you can deactivate at any time from your account settings, which hides your account and content from others. To request full deletion or a copy of your data, contact us (see Your Rights).
6. Cookies & Browser Storage
- qMEET uses only sign-in and security cookies (authentication, session, “remember me,” security-stamp, and trusted-device) plus a few small functional flags (screen size, time zone, invite referral). We do not use advertising or cross-site tracking cookies, and the site’s Content-Security-Policy blocks third-party trackers.
- We store a few values in your browser’s local storage — scroll positions, one-time “don’t show again” flags, and unsent work (your signup and Contact Us drafts, your last live-chat message) so you don’t lose typing; drafts clear once submitted. No password, authentication token, or session identifier is stored there.
7. How Long We Keep Your Information
- We keep your account and content for as long as your account is active. Deactivating your account hides your data; contact us to have it deleted.
- Direct messages are auto-deleted on the schedule you set in Preferences.
- Security and audit-log records are kept for as long as needed to keep the service secure and to meet legal obligations, then removed.
8. Your Rights
- Depending on where you live (for example, the EEA or UK under the GDPR, or California under the CCPA/CPRA), you may have the right to access, correct, delete, or receive a copy of your personal information, to object to or restrict certain processing, and to withdraw consent.
- You can exercise many of these directly — edit your information on My Profile, adjust sharing in Preferences, and deactivate your account in your account settings. For access, a copy of your data, or full deletion, contact us through Contact Us and we will respond within a reasonable time.
- We will not discriminate against you for exercising these rights. If you are in the EEA or UK, you also have the right to complain to your local data-protection authority.
9. Children’s Privacy
- qMEET is intended for adults. You must be at least 18 years old to create an account. We do not knowingly collect personal information from anyone under 18; if we learn that we have, we will delete it. If you believe a minor has provided us information, please contact us.
10. How We Protect Your Information
- qMEET is served only over encrypted HTTPS; sign-in and “remember me” tokens are stored only as hashes; access to your data is re-checked on every operation; and content is filtered for abuse. The cards below describe these protections in detail. No online service can be completely secure, but we work to protect your information and to respond quickly if something goes wrong.
11. Where Your Information Is Processed
- qMEET is operated and hosted in the United States. If you access qMEET from another country, your information is processed in the United States, which may have different data-protection laws than your own.
12. Changes to This Policy
- We may update this Privacy Policy from time to time. When we do, we’ll change the “Last updated” date above and tell you about significant changes within the app. Continuing to use qMEET after an update means you accept the revised policy.
Site-Wide Security
Data Protection
- All database queries use parameterized statements, which prevents SQL injection attacks.
- User-provided content is HTML-encoded before being displayed, preventing cross-site scripting (XSS) attacks.
- Server-side validation is performed on all inputs independently of any client-side validation.
- Field length limits are enforced server-side against actual database column sizes.
Authentication & Session Management
- Authentication uses an encrypted and cryptographically signed Forms Authentication ticket.
- If your session data is lost (for example, after a server restart), it is automatically rebuilt from your valid authentication ticket in
Global.asax — you remain logged in without re-entering your credentials.
- Sessions use non-default cookie names (
QMEETSESSION and .QMeetAuth) to reduce automated targeting.
- The authentication ticket is decrypted inside an error-handling block — malformed or tampered cookies are silently discarded rather than causing an application error.
- Session data is loaded from the database once per request via
PopulateSessionForAuthenticatedUser and held in memory for that request's lifetime, ensuring all code within a single request sees consistent values.
Access Control
- Authorization is verified independently on every sensitive operation, not just when a page first loads.
- Authentication state is re-evaluated on every page load and every AJAX call. There is no endpoint that trusts a check performed during a prior request.
- Event and group membership / organizer permissions are checked on every read, write, and delete operation via
IsEventMemberAndNotBanned, IsEventOrganizerAndNotBanned, and their group counterparts.
Security Headers
The following security headers are sent with every response:
- X-Content-Type-Options: nosniff — prevents browsers from guessing content types, stopping MIME-sniffing attacks that could cause a non-HTML response to be interpreted and executed as a script.
- X-Frame-Options: SAMEORIGIN — prevents the site from being embedded in iframes hosted on other origins, protecting against clickjacking and UI-redress attacks.
- Referrer-Policy: strict-origin-when-cross-origin — sends only the origin (not the full URL) to third-party sites when you follow a link, preventing path and query-string data from leaking to external destinations.
- Permissions-Policy — disables browser APIs the application does not use (microphone, camera, payment, USB, motion sensors, Topics API), so even a fully compromised script running on the page cannot prompt for access to them. Geolocation is permitted only for qMEET’s own origin (
self), because qMEET uses it for optional check-ins and location-aware features — see the Privacy Policy above for exactly how location is collected, who can see it, and how to turn it off.
- Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Resource-Policy: same-origin — cross-origin isolation hints that strengthen the browser's process boundary against Spectre-class attacks.
- Strict-Transport-Security (HSTS): max-age=31536000; includeSubDomains — instructs browsers to use HTTPS exclusively for one full year, covering the entire qmeet.net domain and every subdomain. Once received, the browser refuses plain-HTTP downgrades even if a user attempts to type an
http:// URL.
- The HSTS header is applied conditionally — only on responses served over a verified HTTPS connection (including those proxied via
X-Forwarded-Proto by Plesk), and never on localhost requests. This prevents a developer's local environment from being permanently locked to HTTPS-only.
- Content-Security-Policy (CSP) — restricts where browser content can be loaded from.
default-src 'self' blocks all third-party origins by default; connect-src 'self' https://*.onesignal.com blocks cross-origin AJAX/fetch calls except to the push-notification provider; frame-ancestors 'self' reinforces the X-Frame-Options block at the modern-CSP layer; form-action 'self' prevents any form on the site from being repointed to submit user data to an external domain; base-uri 'self' prevents a <base> tag from being injected to relocate every relative URL; and object-src 'none' blocks embedding plugin objects altogether.
- Beyond the directives above, the Content-Security-Policy also constrains
script-src, style-src, img-src, font-src, and frame-src. Scripts and frames are limited to the site’s own origin plus the OneSignal push endpoints; every other third-party script, stylesheet, frame, or websocket origin is refused by the browser.
- The deprecated X-XSS-Protection header is explicitly removed from every response. Its legacy filter could itself be abused to selectively disable legitimate script, and modern browsers ignore it; stripping it ensures no stale platform default re-introduces that risk. The Content-Security-Policy is the documented replacement.
- The
X-Powered-By, X-AspNet-Version, and IIS Server response headers are removed from every response, preventing automated scanners from identifying the server technology stack.
- Security headers are emitted by two independent mechanisms: the IIS
<httpProtocol> block in Web.config (for production IIS) and the Application_BeginRequest handler in Global.asax (for IIS Express and other development environments). Both layers must fail simultaneously for a header to be missing from a response.
ViewState & Form Integrity
- All ViewState is cryptographically signed (Message Authentication Code) and encrypted (
viewStateEncryptionMode="Auto"). The encrypted, MAC-protected ViewState cannot be read by an attacker and cannot be modified without invalidating the signature.
- EventValidation is enabled site-wide. The framework records the set of legitimate postback target IDs and event values when a page is rendered, and rejects any postback containing an event from a source not present in that original set. Attempts to fabricate postback events for hidden or disabled controls are rejected at the framework level before any application code runs.
- ViewState is bound to your current session via
ViewStateUserKey, which is set in the OnInit stage of every page that inherits BasePage — the earliest valid point in the page lifecycle. ViewState submitted in one user's session cannot be replayed by another user, even if the raw bytes are captured.
Input Filtering
- String values processed by application code are passed through a centralized sanitization step (
SecurityHelper.Sanitize) that trims leading and trailing whitespace and truncates the value to a field-specific maximum length before storage. This normalization is applied uniformly via a shared helper rather than ad hoc per page, ensuring consistent enforcement across all input paths.
- All user-supplied strings rendered back to the browser are passed through
HttpUtility.HtmlEncode() at the render site — not at the input boundary. Output encoding is applied where the data is consumed (the page rendering it), so a record that was inserted into the database before output encoding was applied at that location is still safely rendered now.
- The output-encoding rule applies uniformly to every user-controllable value rendered into HTML: event/group names, descriptions, location and address fields, chat messages, interest labels, member display names, the IP address shown on the login page, error messages echoed back from validation, and feedback text rendered for moderation.
validateRequest="false" is set site-wide because chat and feedback fields legitimately accept <, >, and quote characters. XSS defense relies on output encoding at the render site rather than on input validation at the request boundary.
Cookie & Token Handling
- Authentication tokens and session IDs are never placed in URLs — they are stored in cookies only (
cookieless="UseCookies"). This prevents tokens from appearing in server logs, browser history, address-bar copies, or HTTP Referer headers when following an outbound link.
- The Forms Authentication ticket is protected with
protection="All" — the cookie payload is both AES-encrypted (so its contents cannot be inspected) and HMAC-signed (so a single-byte modification invalidates the entire ticket). Tampering, partial forgery, and replay-after-decryption attempts all fail at the framework layer before any application code reads the ticket.
- Cross-application authentication redirects are disabled (
enableCrossAppRedirects="false"), preventing authentication tickets from being accepted by other applications on the same server or domain.
- Both the session cookie (
QMEETSESSION) and the authentication cookie (.QMeetAuth) are set with SameSite=Lax. Browsers will not send these cookies on cross-site POST requests or with cross-site embedded resources, blocking a wide class of CSRF attacks at the cookie-delivery layer.
- A site-wide default in
<httpCookies> applies HttpOnly=true and SameSite=Lax to every cookie the application emits, including cookies created without an explicit policy. A developer cannot accidentally introduce a JavaScript-readable cookie by forgetting to set the flag.
- The
Secure flag is applied to every outbound cookie on HTTPS requests by Global.asax Application_EndRequest. Because Plesk terminates SSL before IIS, the framework's Request.IsSecureConnection returns false on the backend; the EndRequest pass reads X-Forwarded-Proto via SecurityHelper.IsRequestSecure and explicitly sets Secure=true when the request is real HTTPS.
- Expired session IDs are regenerated rather than reused (
regenerateExpiredSessionId="true"), preventing session fixation attacks that rely on planting a known-expired identifier and waiting for it to be reissued.
Rate Limiting
- Rate limiting is applied independently to multiple sensitive operations, each with its own attempt threshold and time window: login, password reset, contact form, account creation (Join), and invite sending.
- All rate-limiting counters are stored in server-side memory via
SecurityHelper.IsThrottled. They cannot be reset by clearing cookies, opening a private browser window, or starting a new session.
- The contact form applies two independent rate limits simultaneously: one keyed to the submitter's IP address, and a second keyed to their authenticated user account. A user rotating IP addresses cannot bypass the per-account limit, and a shared network cannot exhaust the per-IP limit for all of its users simultaneously.
Client IP Detection
- The IP address used for all rate-limiting decisions and audit-logging is resolved in a proxy-aware manner: the
X-Forwarded-For request header is read first via SecurityHelper.GetClientIP, enabling accurate client attribution when traffic passes through Plesk's reverse proxy. The direct connection address is used as a fallback when no forwarding header is present. This ensures throttle keys and security event logs attribute activity to the actual client rather than the intermediary.
Search Engine & Crawler Controls
- Sensitive pages — including login, dashboard, chat, manage-event/group, account, and contact-us submission pages — carry
noindex, nofollow directives. Search engines cannot index these pages or follow their links.
- A site-wide
robots.txt instructs all search engine crawlers to avoid account-, chat-, and management-related pages.
Error Handling
- Friendly, generic error messages are shown to users — raw technical detail (stack traces, SQL text, file paths) is never exposed to ordinary users.
- Every unhandled exception is logged to the audit trail (
plp_Logs) with full request context — the request URL, HTTP method, user IP, session ID, and the complete exception chain including inner exceptions up to five levels deep — so failures can be investigated from the log without surfacing any detail to the user.
- Every unhandled server error is assigned a correlation ID: the full identifier is written to the log row and a short 8-character token is shown on the error page, so a user can quote it to support and have the exact incident located — without the page ever exposing the underlying exception.
- Every exception also appends to a size-capped, self-rotating diagnostic flat-file (
App_Data/last_errors.txt, ~5 MB rotation) — this catches crashes that happen mid-response-flush where the redirect to Error.aspx cannot complete cleanly. The file lives under App_Data, which IIS never serves over HTTP.
- 404 Not Found errors are treated as a distinct case: logged at warning level with the requested URL and authenticated user context, then redirected to a generic error page. Internal file paths, directory structure, and the presence of protected files are never revealed in the response.
- 401 Unauthorized HTTP responses are silently promoted to 403 Forbidden and redirected to the same generic error page. This prevents an attacker from distinguishing between “resource does not exist” and “resource exists but requires authentication.”
- The short correlation token echoed onto the error page from the
?cid= query string is rendered only when it matches a strict ^[A-Z0-9]{1,16}$ allowlist pattern; any value carrying markup or other characters is dropped, so the reflected reference token can never become a reflected-XSS vector.
- Any transient diagnostic note stashed server-side for the error page is consumed and cleared on every error-page render — even when it is not displayed — so a detail captured during one request can never linger into a later, unrelated request, including on a shared device.
Security Logging
- Security-relevant events are logged with IP address, browser information, and timestamp into the
plp_Logs table via LoggingService. Distinct severity levels (INFO, WARN, ERROR, CRITICAL, AUDIT, SECURITY) and category tags (Login, LoginFailed, AccessDenied, SecurityViolation, Suspicious, Delete, Update, Exception, PageVisit, ClientData) make it possible to filter the audit trail to a specific event class.
- When you visit key pages, your IP address, browser, device type, OS, screen resolution, language, and timezone are recorded. This information is used to identify and respond to unauthorized access attempts and to reconstruct incidents from the audit trail.
- Every log entry is timestamped with the session ID, allowing the activity of a single session to be reconstructed even when the session has since been abandoned or expired.
- All logging operations are wrapped in exception handlers — a failure to write a log entry cannot crash or degrade the application. The user's operation continues even if the audit-trail database is briefly unavailable.
- Log field values are individually truncated to their database column limits before insertion. Oversized inputs cannot trigger a database error mid-log-write and cannot be used as a log-injection or buffer-style attack vector.
- Log entries generated from unauthenticated flows (account recovery, the contact form) record only a masked rendering of any email or phone the user typed (
j***@gmail.com, ***-4567), so the audit trail supports abuse correlation without persisting recoverable personal data.
- Redirect-driven
ThreadAbortExceptions are filtered out of the audit writer, so the log isn’t spammed with framework-normal exceptions and the trail stays focused on genuine events.
Maintenance Mode
- The site can be placed in maintenance mode via a single Web.config flag. When enabled,
Application_PostAuthenticateRequest in Global.asax intercepts every request — pages, AJAX WebMethods, .ashx handlers — and redirects to Maintenance.aspx with HTTP 503 + a Retry-After header.
- The maintenance page itself plus the static assets it depends on (Content, Scripts, Images, Sounds, favicon, manifest, service-worker, and PWA icons) are bypassed so the page always renders correctly with its styling and icons even while the rest of the site is closed.
Logout & Session Termination
- Logging out invokes
FormsAuthentication.SignOut() to revoke the authentication ticket, then Session.Clear(), Session.RemoveAll(), and Session.Abandon() to wipe and tear down the server-side session container.
- Beyond the framework calls, the authentication cookie (
.QMeetAuth) and the session cookie (QMEETSESSION) are each explicitly overwritten with an empty, past-dated value. The replacement auth cookie is marked HttpOnly, SameSite=Lax, and Secure whenever the originating request was genuine HTTPS (read from X-Forwarded-Proto via SecurityHelper.IsRequestSecure, since Plesk terminates TLS before the request reaches the application). This belt-and-suspenders deletion forces client-side removal even on browsers that do not reliably honour cookie removal from SignOut()/Abandon() alone — otherwise the persistent ticket would silently rebuild the session on the next request.
- Any legacy credential cookies left behind by older versions of the site are proactively expired at logout as well, so a stale value cannot survive the sign-out on a returning browser.
- The logout event is logged — including user ID and IP address — before the session is cleared, ensuring the audit trail is never lost.
Outbound Email Security
- All outbound email is transmitted over an encrypted SMTP connection using TLS on port 587. The
enableSsl setting in Web.config mandates encryption — plaintext delivery is not possible.
- SMTP server credentials are read from
Web.config at runtime via the framework's system.net/mailSettings section. The SmtpClient instances used in application code do not contain hardcoded credentials.
- The SMTP client timeout is explicitly capped at 15 seconds (overriding the framework default of 100 seconds) in
EmailService. A slow or unreachable mail server cannot pin a request thread for an extended period.
- When an outbound email fails, the SMTP error detail (authentication failures, RFC 5321 reply codes, mail-host names) is logged server-side but never returned to the user — the caller receives only a generic “delivery failed” marker, so transport internals cannot leak into a user-facing message.
- Email subjects are sanitized by stripping CR/LF and clamping length, so a user-supplied value flowing into a subject cannot inject additional SMTP headers.
- Email send operations are wrapped in their own exception handlers. A mail-server outage cannot prevent the underlying user action from completing or the error page from being shown to the user.
- Outbound email message and SMTP client objects are wrapped in
Using blocks so the underlying network socket is closed immediately after the send completes, even if an exception bubbles up from the SMTP transport.
Built-in Provider Isolation
- The legacy ASP.NET built-in Membership and Role providers have been explicitly removed via
<clear /> directives in Web.config. No application code or framework component can accidentally invoke default provider implementations.
- The ASP.NET RoleManager is disabled entirely (
enabled="false"). Authorization decisions are made exclusively by application code reading from session data — the framework's built-in role infrastructure plays no part.
CSRF Protection for AJAX, WebMethods, and Handlers
- Every authenticated request issued by the page receives a per-session CSRF token, generated as a cryptographically random GUID and stored only in server-side session memory. The token is exposed to client JavaScript through a single inline assignment (
window.qmeetCsrfToken) injected by BasePage at render time; it is never written to a cookie, never embedded in a URL, and never reflected into the DOM as an attribute.
- The shared AJAX helper (
QMeet.callMethod) reads the token on every call and forwards it as a custom X-QMeet-CSRF request header. State-changing WebMethods and HTTP handlers (chat, ContactUsLog, etc.) invoke SecurityHelper.ValidateCsrfToken() as their first action — before any database query runs.
- Cross-origin AJAX delivery of the token is impossible: the
X-QMeet-CSRF header is not a CORS-safelisted header, so any cross-origin fetch or XMLHttpRequest that attempts to set it triggers a CORS preflight. The server never answers that preflight with an Access-Control-Allow-Origin grant, so the browser blocks the request before the real call is sent.
- The submitted token is compared against the stored session token in constant time — the comparison inspects every character regardless of where the first mismatch occurs, denying a network-adjacent attacker a timing side-channel for recovering the token byte by byte.
- When a token goes stale (after a deploy or an app-pool recycle with the tab still open), the server tags the rejected response X-QMeet-CSRF-Status: expired and the client transparently fetches a fresh token from a dedicated refresh handler and retries the call once. That refresh handler is itself authentication-gated and rate-limited to 20 requests per minute per user, so the recovery path cannot be abused to enumerate or brute-force tokens.
- When the token is emitted into the page it is passed through
HttpUtility.JavaScriptStringEncode, so neither the token nor the adjacent localized message strings can break out of their JavaScript string literal and inject script into the page.
- The token-refresh handler’s JSON response is itself marked
no-cache / no-store so neither a proxy nor the browser can retain a token value; it returns the (re-)generated session token JavaScript-string-encoded; and a client that exceeds the 20-per-minute ceiling receives an HTTP 429 with that breach recorded in the audit trail.
Cryptographic Discipline
- Every per-session secret — the AJAX CSRF token, per-form login and contact-form CSRF tokens — is generated from
Guid.NewGuid(), which on .NET draws from the OS cryptographic random source. No security-relevant identifier is derived from a counter, timestamp, or predictable seed.
- ViewState integrity uses the framework's default HMAC algorithm with the machine key. No application code attempts to roll its own MAC or hash for ViewState; the framework primitive is used exactly as designed.
- The framework’s cryptographic keys are explicitly pinned in configuration (
<machineKey> with validation="HMACSHA256" and decryption="AES") rather than being auto-generated per worker. A MAC-signed ViewState payload or an encrypted Forms Authentication ticket therefore stays valid across application-pool recycles and is verified identically by every worker process, with no key-rotation window for an attacker to exploit; the keys are unique to qMEET, so a ticket minted here is never honoured by a sister application.
- The modern
Cryptography.EncryptString / DecryptString helpers use AES-256-CBC + PBKDF2 (100,000 iterations, SHA-256) + per-record salt + IV + HMAC tag, in an encrypt-then-MAC construction: decryption recomputes the HMAC-SHA-256 tag over the salt, IV, and ciphertext and rejects the input on a constant-time mismatch before any plaintext is produced — closing both padding-oracle and tag-timing side channels. Legacy Rijndael/TripleDES helpers exist for backwards-compatibility with already-encrypted data but are not used for new encryption.
Time Handling
- UTC timestamps from the database (
FeedbackDate, ClosedDatetime, etc.) are converted to the user's local time zone only at render time, using a TimeZoneInfo.Id from the user's profile. Conversion is performed inside a try/catch via DateHelper.ToUserLocalTime — an unrecognised time-zone ID falls back to server-local time rather than throwing a rendering exception.
- Displayed dates and times use a consistent format (no leading zeros, e.g.
12/26/2026 5:31 PM) via the shared DateHelper helpers, so a user-controlled value cannot influence the surface format and slip past parsing somewhere.